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 . */ 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); +}