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