Hi, I've implemented a replacement for m_o_lock_request (called m_o_sync_request) that helps to prevent thread storms in ext2fs when synchronizing large pagers, by giving translators the ability to throttle the amount of m_o_data_return request that are going to be received.
When using this interface, thread storms can still appear in some situations, like when creating a large number of files sequentially (when object's cache list is full, GNU Mach will start cleaning it, triggering a race of pageouts between vm_object_terminate and synchronization thread of ext2fs) or when memory is almost exhausted. These situations would be solved with a new cache system for memory objects (and this is something we should start working on ASAP). I also needed to change m_o_terminate interface to prevent RPCs to get stuck (I've described this problem in a previous mail). We didn't notice this previously because before m_o_sync_request, the only RPC for memory object was m_o_get_attributes, which is not currently in use by Hurd. 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. Thanks!
diff -dur gnumach.orig/include/mach/mach.defs gnumach.tmp/include/mach/mach.defs --- gnumach.orig/include/mach/mach.defs 2010-05-04 11:56:55.000000000 +0200 +++ gnumach.tmp/include/mach/mach.defs 2010-05-12 16:16:48.000000000 +0200 @@ -409,17 +409,18 @@ reply_to : mach_port_t = MACH_MSG_TYPE_MAKE_SEND_ONCE|polymorphic); -/* obsolete */ -routine xxx_task_get_emulation_vector( - task : task_t; - out vector_start : int; - out emulation_vector: xxx_emulation_vector_t, IsLong); -/* obsolete */ -routine xxx_task_set_emulation_vector( - task : task_t; - vector_start : int; - emulation_vector: xxx_emulation_vector_t, IsLong); +routine memory_object_sync_request( + memory_control : memory_object_control_t; + offset : vm_offset_t; + size : vm_size_t; + should_return : memory_object_return_t; + should_flush : boolean_t; + out dirty : boolean_t; + out start_offset : vm_offset_t; + out end_offset : vm_offset_t); + +skip; /* * Returns information about the host on which the diff -dur gnumach.orig/include/mach/memory_object.defs gnumach.tmp/include/mach/memory_object.defs --- gnumach.orig/include/mach/memory_object.defs 2010-05-04 11:56:55.000000000 +0200 +++ gnumach.tmp/include/mach/memory_object.defs 2010-05-12 16:16:48.000000000 +0200 @@ -85,25 +85,10 @@ simpleroutine memory_object_terminate( memory_object : memory_object_t = MACH_MSG_TYPE_MOVE_SEND - ctype: mach_port_t; + ctype: mach_port_t #if SEQNOS - msgseqno seqno : mach_port_seqno_t; +; msgseqno seqno : mach_port_seqno_t; #endif /* SEQNOS */ - memory_control : memory_object_control_t = - MACH_MSG_TYPE_MOVE_RECEIVE - ctype: mach_port_t -#if KERNEL_USER - /* for compatibility with Mach 2.5 kernels */ - , dealloc -#endif /* KERNEL_USER */ - ; - memory_object_name : memory_object_name_t = - MACH_MSG_TYPE_MOVE_RECEIVE - ctype: mach_port_t -#if KERNEL_USER - /* for compatibility with Mach 2.5 kernels */ - , dealloc -#endif /* KERNEL_USER */ ); /* diff -dur gnumach.orig/vm/memory_object.c gnumach.tmp/vm/memory_object.c --- gnumach.orig/vm/memory_object.c 2010-05-04 11:56:55.000000000 +0200 +++ gnumach.tmp/vm/memory_object.c 2010-05-12 16:16:46.000000000 +0200 @@ -892,6 +892,201 @@ } /* + * Routine: memory_object_sync_request [user interface] + * + * Description: + * This is a specialized version of m_o_lock_request for + * syncing memory objects. These are the differences between + * them: + * 1) if dirty pages are found, stops processing + * and sends them to the pager. Sets start_offset + * to the head of first dirty page, and end_offset + * to the end of last one. + * 3) doesn't change protection level. + * 4) as this is a RPC, there's no need for a reply + * port. + * The set of pages is defined by a starting offset + * ("offset") and size ("size"). Only pages with the + * same page alignment as the starting offset are + * considered. + */ +kern_return_t +memory_object_sync_request(object, offset, size, + should_return, should_flush, dirty, + start_offset, end_offset) + register vm_object_t object; + register vm_offset_t offset; + register vm_size_t size; + memory_object_return_t should_return; + boolean_t should_flush; + boolean_t *dirty; + vm_offset_t *start_offset; + vm_offset_t *end_offset; +{ + register vm_page_t m; + vm_offset_t original_offset = offset; + vm_size_t original_size = size; + vm_offset_t paging_offset = 0; + vm_object_t new_object = VM_OBJECT_NULL; + vm_offset_t new_offset = 0; + vm_offset_t first_offset = -1; + vm_offset_t last_offset = offset; + int page_lock_result; + int pageout_action = 0; /* '=0' to quiet lint */ + + /* + * We use DATA_WRITE_MAX and PAGEOUT definitions from + * m_o_lock_request. + */ + vm_page_t holding_pages[DATA_WRITE_MAX]; + + /* + * Check for bogus arguments. + */ + if (object == VM_OBJECT_NULL) + return (KERN_INVALID_ARGUMENT); + + size = round_page(size); + + /* + * Lock the object, and acquire a paging reference to + * prevent the memory_object and control ports from + * being destroyed. + */ + + vm_object_lock(object); + vm_object_paging_begin(object); + offset -= object->paging_offset; + + /* + * Search for a block of continuous pages to return to + * the pager. + */ + for (; + size != 0; + size -= PAGE_SIZE, offset += PAGE_SIZE) + { + /* + * If we have DATA_WRITE_MAX pages, stop searching. + */ + if (new_object != VM_OBJECT_NULL && + new_offset >= PAGE_SIZE * DATA_WRITE_MAX) + break; + + if ((m = vm_page_lookup(object, offset)) == VM_PAGE_NULL) + break; + + page_lock_result = memory_object_lock_page(m, + should_return, + should_flush, + VM_PROT_NO_CHANGE); + + if (page_lock_result == MEMORY_OBJECT_LOCK_RESULT_DONE) { + if (new_object != VM_OBJECT_NULL) { + /* + * We have found a clean page, after a group of + * dirty ones. Stop searching and return them. + */ + break; + } + continue; + } + else if (page_lock_result == + MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK) { + /* + * We need to block to return this page. If + * we have other pages pending, stop searching + * and return them. + */ + if (new_object != VM_OBJECT_NULL) { + break; + } + + printf("mosr: must block, waiting\n"); + + PAGE_ASSERT_WAIT(m, FALSE); + vm_object_unlock(object); + thread_block((void (*)()) 0); + vm_object_lock(object); + + printf("mosr: must block, continuing\n"); + + /* + * Check the same page again. + */ + size += PAGE_SIZE; + offset -= PAGE_SIZE; + continue; + } + else { + /* + * Mark the page busy. + */ + m->busy = TRUE; + vm_object_unlock(object); + + /* + * If we have not already allocated an object + * for a range of pages to be written, do so + * now. + */ + if (new_object == VM_OBJECT_NULL) { + new_object = vm_object_allocate(DATA_WRITE_MAX); + new_offset = 0; + paging_offset = m->offset + + object->paging_offset; + pageout_action = page_lock_result; + } + + /* + * Move or copy the dirty page into the + * new object. + */ + m = vm_pageout_setup(m, + m->offset + object->paging_offset, + new_object, + new_offset, + should_flush); + + /* + * Save the holding page if there is one. + */ + holding_pages[atop(new_offset)] = m; + + if (first_offset == -1) + first_offset = offset; + new_offset += PAGE_SIZE; + last_offset = offset + PAGE_SIZE; + + vm_object_lock(object); + } + } + + /* + * We have completed the scan for applicable pages. + * Clean any pages that have been saved, and set dirty, + * start_offset and end_offset properly. + */ + if (new_object != VM_OBJECT_NULL) { + PAGEOUT_PAGES; + *dirty = TRUE; + *start_offset = first_offset; + *end_offset = last_offset; + } + else { + *dirty = FALSE; + *start_offset = 0; + *end_offset = 0; + } + + vm_object_paging_end(object); + vm_object_unlock(object); + vm_object_deallocate(object); + + return (KERN_SUCCESS); +} + +/* * Old version of memory_object_lock_request. */ kern_return_t diff -dur gnumach.orig/vm/vm_object.c gnumach.tmp/vm/vm_object.c --- gnumach.orig/vm/vm_object.c 2010-05-04 11:56:55.000000000 +0200 +++ gnumach.tmp/vm/vm_object.c 2010-05-12 16:16:46.000000000 +0200 @@ -710,9 +710,13 @@ ip_reference(pager); /* - * Terminate the pager. + * Dealloc ports and terminate the pager. */ - (void) memory_object_terminate(pager, pager_request, pager_name); + + ipc_port_dealloc_kernel(pager_request); + ipc_port_dealloc_kernel(pager_name); + + (void) memory_object_terminate(pager); /* * Wakeup anyone waiting for this terminate
diff -dur hurd-deb.orig/ext2fs/pager.c hurd/ext2fs/pager.c --- hurd-deb.orig/ext2fs/pager.c 2010-05-06 11:37:31.000000000 +0200 +++ hurd/ext2fs/pager.c 2010-05-12 15:44:02.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); } diff -dur hurd-deb.orig/libpager/data-request.c hurd/libpager/data-request.c --- hurd-deb.orig/libpager/data-request.c 2010-05-06 11:37:31.000000000 +0200 +++ hurd/libpager/data-request.c 2010-05-11 20:42:04.000000000 +0200 @@ -61,23 +61,16 @@ goto release_out; } - _pager_block_termination (p); /* prevent termination until - mark_object_error is done */ - if (p->pager_state != NORMAL) { printf ("pager in wrong state for read\n"); - _pager_allow_termination (p); goto release_out; } err = _pager_pagemap_resize (p, offset + length); if (err) - { - _pager_allow_termination (p); - goto release_out; /* Can't do much about the actual error. */ - } - + goto release_out; /* Can't do much about the actual error. */ + /* If someone is paging this out right now, the disk contents are unreliable, so we have to wait. It is too expensive (right now) to find the data and return it, and then interrupt the write, so we just @@ -128,7 +121,6 @@ MACH_PORT_NULL); mutex_lock (&p->interlock); _pager_mark_object_error (p, offset, length, 0); - _pager_allow_termination (p); mutex_unlock (&p->interlock); ports_port_deref (p); return 0; @@ -138,7 +130,6 @@ _pager_mark_object_error (p, offset, length, EIO); allow_term_out: mutex_lock (&p->interlock); - _pager_allow_termination (p); mutex_unlock (&p->interlock); ports_port_deref (p); return 0; diff -dur hurd-deb.orig/libpager/data-return.c hurd/libpager/data-return.c --- hurd-deb.orig/libpager/data-return.c 2010-05-06 11:37:31.000000000 +0200 +++ hurd/libpager/data-return.c 2010-05-12 22:02:03.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); @@ -86,13 +79,27 @@ memset (notified, -1, npages * (sizeof *notified)); #endif - _pager_block_termination (p); /* until we are done with the pagemap - when the write completes. */ - _pager_pagemap_resize (p, offset + length); 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. */ @@ -105,10 +112,8 @@ } if (! dirty) - { - _pager_allow_termination (p); - goto release_out; - } + goto release_out; + /* Make sure there are no other in-progress writes for any of these pages before we begin. This imposes a little more serialization @@ -140,23 +145,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,15 +206,16 @@ 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: - _pager_allow_termination (p); mutex_unlock (&p->interlock); for (i = 0; i < npages; i++) diff -dur hurd-deb.orig/libpager/data-unlock.c hurd/libpager/data-unlock.c --- hurd-deb.orig/libpager/data-unlock.c 2010-05-06 11:37:31.000000000 +0200 +++ hurd/libpager/data-unlock.c 2010-05-11 20:42:04.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 hurd-deb.orig/libpager/lock-object.c hurd/libpager/lock-object.c --- hurd-deb.orig/libpager/lock-object.c 2010-05-06 11:37:31.000000000 +0200 +++ hurd/libpager/lock-object.c 2010-05-12 15:46:10.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 hurd-deb.orig/libpager/Makefile hurd/libpager/Makefile --- hurd-deb.orig/libpager/Makefile 2010-05-06 11:37:31.000000000 +0200 +++ hurd/libpager/Makefile 2010-05-12 13:49:34.000000000 +0200 @@ -20,12 +20,11 @@ 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 \ + sync-object.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 + dropweak.c notify-stubs.c get-upi.c pager-memcpy.c pager-return.c LCLHDRS = pager.h priv.h installhdrs = pager.h diff -dur hurd-deb.orig/libpager/object-terminate.c hurd/libpager/object-terminate.c --- hurd-deb.orig/libpager/object-terminate.c 2010-05-06 11:37:31.000000000 +0200 +++ hurd/libpager/object-terminate.c 2010-05-12 15:37:58.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,27 +34,7 @@ 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; - } - - while (p->noterm) - { - p->termwaiting = 1; - 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); + /* Mach has already destroyed the ports, reflect it in P. */ p->memobjcntl = p->memobjname = MACH_PORT_NULL; _pager_free_structure (p); @@ -76,7 +54,6 @@ } #endif - out: _pager_release_seqno (p, seqno); mutex_unlock (&p->interlock); ports_port_deref (p); @@ -97,9 +74,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 hurd-deb.orig/libpager/pager-flush.c hurd/libpager/pager-flush.c --- hurd-deb.orig/libpager/pager-flush.c 2010-05-06 11:37:31.000000000 +0200 +++ hurd/libpager/pager-flush.c 2010-05-11 20:42:04.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 hurd-deb.orig/libpager/pager-return.c hurd/libpager/pager-return.c --- hurd-deb.orig/libpager/pager-return.c 2010-05-06 11:37:31.000000000 +0200 +++ hurd/libpager/pager-return.c 2010-05-11 20:42:04.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 hurd-deb.orig/libpager/pager-sync.c hurd/libpager/pager-sync.c --- hurd-deb.orig/libpager/pager-sync.c 2010-05-06 11:37:31.000000000 +0200 +++ hurd/libpager/pager-sync.c 2010-05-11 20:42:04.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 hurd-deb.orig/libpager/priv.h hurd/libpager/priv.h --- hurd-deb.orig/libpager/priv.h 2010-05-06 11:37:31.000000000 +0200 +++ hurd/libpager/priv.h 2010-05-12 15:30:57.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 @@ -135,15 +135,14 @@ void _pager_wait_for_seqno (struct pager *, int); void _pager_release_seqno (struct pager *, int); void _pager_stubs_update_seqno (mach_port_t, int); -void _pager_block_termination (struct pager *); -void _pager_allow_termination (struct pager *); error_t _pager_pagemap_resize (struct pager *, vm_address_t); void _pager_mark_next_request_error (struct pager *, vm_address_t, vm_size_t, error_t); 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 hurd-deb.orig/libpager/stubs.c hurd/libpager/stubs.c --- hurd-deb.orig/libpager/stubs.c 2010-05-06 11:37:31.000000000 +0200 +++ hurd/libpager/stubs.c 2010-05-12 14:51:18.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 hurd-deb.orig/libpager/sync-object.c hurd/libpager/sync-object.c --- hurd-deb.orig/libpager/sync-object.c 2010-05-12 15:46:42.000000000 +0200 +++ hurd/libpager/sync-object.c 2010-05-12 15:47:53.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); +}