diff options
author | Neal H Walfield <neal@cs.uml.edu> | 2002-04-10 17:47:58 -0400 |
---|---|---|
committer | Maksym Planeta <mcsim.planeta@gmail.com> | 2012-09-30 15:07:18 +0300 |
commit | 2ca8719606eeca99c425b3282017a6412b49213a (patch) | |
tree | 7c114b3e300174ef82855e1472aa7caf79dd65ed | |
parent | 62004794b01e9e712af4943e02d889157ea9163f (diff) |
Reworking libpager
* pager.h (struct pager): Bring into scope. (struct
pager_ops): New structure. Contains the call backs: read,
write, unlock, report_extent, clear_user_data and dropweak.
Replaces the linker-time call backs: pager_read_page,
pager_write_page, pager_unlock_page, pager_report_extenet,
pager_clear_user_data and pager_drop_weak. Functions now
also have a multipage interface and take block, not byte,
offsets (i.e. off_t's, not vm_address_t's).
(pager_cleate): Take a struct pager_ops to support new interface.
Take the size of the desired user_page_info structure rather than
a user_pager_info structure to correspond with the new semantics.
(pager_get_error): Follow new semantics: take the page number
rather than a byte offset.
(pager_sync_come): Likewise.
(pager_flush_come): Likewise.
(pager_return_some): Likewise.
(pager_memcpy): Likewise.
(pager_offset_page): Remove obsolete function.
(pager_read_page): Removed in favor of call back in struct
pager_ops.
(pager_write_page): Likewise.
(pager_unlock_page): Likewise.
(pager_report_extent): Likewise.
(pager_clear_user_data): Likewise.
(pager_dropweak): Likewise.
(pager_data_supply): New function.
(pager_data_unavailable): Likewise.
(pager_data_read_error): Likewise.
(pager_data_write_error): Likewise.
(pager_data_unlock): Likewise.
(pager_data_unlock_error): Likewise.
* priv.h (struct pager): Change UPI from a struct user_pager_info
to a flex array at the end of the structure to match the new
pager_create semantics. Add the pager_ops call back structure.
(PM_PAGEINWAIT): Macro no longer used.
(PM_WRITEWAIT): Adjust value.
(PM_INIT): Likewise.
(PM_INCORE): Likewise.
(PM_PAGINGOUT): Likewise.
(_pager_pagemap_resize): Take a block offset, not a byte-offset.
(_pager_mark_next_request_error): Likewise.
(_pager_mark_object_error): Likewise.
(_pager_lock_object): Likewise. P->interlock is now expected to
already be held during the call.
* data-return.c (_pager_do_write_request) Remove obsolete
function.
* data-return.c (_pager_seqnos_memory_object_data_return):
Rewritten to work with the new paging interface.
* data-request.c (_pager_seqnos_memory_object_data_request):
Likewise.
* data-unlock.c (_pager_seqnos_memory_object_data_unlock):
Likewise.
* clean.c (_pager_clean): Use the new call backs in P->ops.
* dropweak.c (_pager_real_dropweak): Likewise.
* lock-completed.c (_pager_seqnos_memory_object_lock_completed):
Handle page offsets and not byte offsets.
* lock-object.c (_pager_lock_object): Handle page offsets and not
byte offsets. As per the new interface, do not lock P->interlock
anymore.
* mark-error.c (_pager_mark_next_request_error): Handle page
offsets and not byte offsets. Use vm_page_size, not
__vm_page_size. Doc fix.
(_pager_mark_object_error): Likewise.
(pager_get_error): Likewise.
* pagemap.c (VMCOPY_BETTER_THAN_MEMCPY): New macro.
(_pager_pagemap_resize): Handle page offsets and not byte
offsets. Use vm_page_size, not __vm_page_size. Allocate the
minimum number of pages. Check the result of mmap against
MAP_FAILED, not -1. Use mempcy, not bcopy. Use vm_copy when
appropriate.
* object-init.c (_pager_seqnos_memory_object_init): Use
vm_page_size, not __vm_page_size. Check the result of malloc.
* pager-attr.c (pager_change_attributes): Correct a typo. Add an
assert.
* pager-create.c (pager_create): Comform to the new semantics as
outlined in the pager.h changelog entry.
* pager-flush.c (pager_flush): Use the new call backs in P->ops.
Handle page offsets, not byte offsets. Call the corresponding
_some function rather than copy the code.
* pager-return.c (pager_return): Likewise.
* pager-sync.c (pager_sync): Likewise.
* pager-flush.c (pager_flush_some): Handle page offsets and not
byte offsets. Lock P->interlock around _pager_lock_object as per
the new semantics.
* pager-return.c (pager_return_some): Likewise.
* pager-sync.c (pager_sync_some: Likewise.
* pager-memcpy.c (pager_memcpy): Pass the pager offset, not the
byte offset to _pager_get_error. Change OFFSET to an off_t rather
than a vm_address_t as per the new semantics.
* Makefile (SRCS): Remove offer-pager.c. Add
pager-data-read-error.c pager-data-unavailable.c
pager-data-unlock.c pager-data-supply.c pager-data-unlock-error.c
pager-data-write-error.c.
* offer-page.c: Remove obsolete files.
* pager-data-read-error.c: New file.
* pager-data-supply.c: Likewise.
* pager-data-unavailable.c: Likewise.
* pager-data-unlock-error.c: Likewise.
* pager-data-unlock.c: Likewise.
* pager-data-write-error.c: Likewise.
-rw-r--r-- | libpager/Makefile | 4 | ||||
-rw-r--r-- | libpager/clean.c | 5 | ||||
-rw-r--r-- | libpager/data-request.c | 204 | ||||
-rw-r--r-- | libpager/data-return.c | 132 | ||||
-rw-r--r-- | libpager/data-unlock.c | 25 | ||||
-rw-r--r-- | libpager/dropweak.c | 5 | ||||
-rw-r--r-- | libpager/get-upi.c | 2 | ||||
-rw-r--r-- | libpager/lock-completed.c | 10 | ||||
-rw-r--r-- | libpager/lock-object.c | 50 | ||||
-rw-r--r-- | libpager/mark-error.c | 53 | ||||
-rw-r--r-- | libpager/object-init.c | 7 | ||||
-rw-r--r-- | libpager/offer-page.c | 52 | ||||
-rw-r--r-- | libpager/pagemap.c | 50 | ||||
-rw-r--r-- | libpager/pager-attr.c | 3 | ||||
-rw-r--r-- | libpager/pager-create.c | 13 | ||||
-rw-r--r-- | libpager/pager-data-read-error.c | 36 | ||||
-rw-r--r-- | libpager/pager-data-supply.c | 41 | ||||
-rw-r--r-- | libpager/pager-data-unavailable.c | 36 | ||||
-rw-r--r-- | libpager/pager-data-unlock-error.c | 41 | ||||
-rw-r--r-- | libpager/pager-data-unlock.c | 33 | ||||
-rw-r--r-- | libpager/pager-data-write-error.c | 44 | ||||
-rw-r--r-- | libpager/pager-flush.c | 26 | ||||
-rw-r--r-- | libpager/pager-memcpy.c | 2 | ||||
-rw-r--r-- | libpager/pager-return.c | 21 | ||||
-rw-r--r-- | libpager/pager-sync.c | 22 | ||||
-rw-r--r-- | libpager/pager.h | 276 | ||||
-rw-r--r-- | libpager/priv.h | 33 |
27 files changed, 754 insertions, 472 deletions
diff --git a/libpager/Makefile b/libpager/Makefile index 40eed16f..af21031b 100644 --- a/libpager/Makefile +++ b/libpager/Makefile @@ -24,7 +24,9 @@ SRCS = data-request.c data-return.c data-unlock.c pager-port.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 + pager-data-read-error.c pager-data-unavailable.c \ + pager-data-unlock.c pager-data-supply.c pager-data-unlock-error.c \ + pager-data-write-error.c installhdrs = pager.h HURDLIBS= threads ports diff --git a/libpager/clean.c b/libpager/clean.c index e891617f..a3ef1158 100644 --- a/libpager/clean.c +++ b/libpager/clean.c @@ -1,5 +1,5 @@ /* - Copyright (C) 1995, 1996 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 2002 Free Software Foundation, Inc. Written by Michael I. Bushnell. This file is part of the GNU Hurd. @@ -46,5 +46,6 @@ _pager_clean (void *arg) mutex_unlock (&p->interlock); } - pager_clear_user_data (p->upi); + if (p->ops->clear_user_data) + p->ops->clear_user_data ((struct user_pager_info *) &p->upi); } diff --git a/libpager/data-request.c b/libpager/data-request.c index 36725b11..a2a7e382 100644 --- a/libpager/data-request.c +++ b/libpager/data-request.c @@ -25,16 +25,26 @@ kern_return_t _pager_seqnos_memory_object_data_request (mach_port_t object, mach_port_seqno_t seqno, mach_port_t control, - vm_offset_t offset, + vm_offset_t start_address, vm_size_t length, vm_prot_t access) { - struct pager *p; - short *pm_entry; - int doread, doerror; error_t err; - vm_address_t page; - int write_lock; + struct pager *p; + short *pm_entries; + off_t start; + int npages; + + error_t last_error; + int page_count; + int good_pages; + unsigned char *errors = NULL; + + int i; + + DEBUG ("object = %d, seqno = %d,control = %d, start_address = %d, " + "length = %d, access = %d", + object, seqno, control, start_address, length, access); p = ports_lookup_port (0, object, _pager_class); if (!p) @@ -44,18 +54,13 @@ _pager_seqnos_memory_object_data_request (mach_port_t object, mutex_lock (&p->interlock); _pager_wait_for_seqno (p, seqno); - /* sanity checks -- we don't do multi-page requests yet. */ + /* sanity checks. */ if (control != p->memobjcntl) { printf ("incg data request: wrong control port\n"); goto release_out; } - if (length != __vm_page_size) - { - printf ("incg data request: bad length size %zd\n", length); - goto release_out; - } - if (offset % __vm_page_size) + if (start_address % vm_page_size) { printf ("incg data request: misaligned request\n"); goto release_out; @@ -70,68 +75,147 @@ _pager_seqnos_memory_object_data_request (mach_port_t object, goto allow_release_out; } - err = _pager_pagemap_resize (p, offset + length); + start = start_address / vm_page_size; + npages = length / vm_page_size; + + err = _pager_pagemap_resize (p, start + npages); if (err) goto allow_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 - mark the page and have the writing thread do m_o_data_supply when it - gets around to it. */ - pm_entry = &p->pagemap[offset / __vm_page_size]; - if (*pm_entry & PM_PAGINGOUT) + 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 wait for the write to finish and then reread the + requested pages from disk. */ + + pm_entries = &p->pagemap[start]; + + retry: + for (i = 0; i < npages; i ++) + if (pm_entries[i] & PM_PAGINGOUT) + { + pm_entries[i] |= PM_WRITEWAIT; + condition_wait (&p->wakeup, &p->interlock); + goto retry; + } + + last_error = 0; + page_count = 0; + good_pages = 0; + + for (i = 0; i < npages; i ++) { - doread = 0; - *pm_entry |= PM_PAGEINWAIT; + error_t err; + + pm_entries[i] |= PM_INCORE; + + if (pm_entries[i] & PM_INVALID) + /* Data on disk was marked bad. */ + err = PAGE_EIO; + else if (PM_NEXTERROR (pm_entries[i]) != PAGE_NOERR + && (access & VM_PROT_WRITE)) + /* In the process of a request, flush, error. */ + err = PM_NEXTERROR (pm_entries[i]); + else + { + good_pages ++; + + if (last_error) + /* This is the start of a good range. Flush the pending + error. */ + err = 0; + else + continue; + } + + if (err == last_error) + page_count ++; + else + { + if (!errors) + { + errors = alloca (sizeof (*errors) * npages); + memset (errors, 0, sizeof (*errors) * npages); + } + + if (last_error) + { + off_t range_start = start + i - page_count; + + /* Record the bad pages. */ + memset (errors + i - page_count, ~0, + sizeof (*errors) * page_count); + + /* Tell the kernel about it. */ + memory_object_data_error (control, range_start * vm_page_size, + page_count * vm_page_size, + _pager_page_errors[last_error]); + _pager_mark_object_error (p, range_start, page_count, + _pager_page_errors[last_error]); + } + + last_error = err; + page_count = 1; + } } - else - doread = 1; - - if (*pm_entry & PM_INVALID) - doerror = 1; - else - doerror = 0; - *pm_entry |= PM_INCORE; - - if (PM_NEXTERROR (*pm_entry) != PAGE_NOERR && (access & VM_PROT_WRITE)) + if (last_error) { - memory_object_data_error (control, offset, length, - _pager_page_errors[PM_NEXTERROR (*pm_entry)]); - _pager_mark_object_error (p, offset, length, - _pager_page_errors[PM_NEXTERROR (*pm_entry)]); - *pm_entry = SET_PM_NEXTERROR (*pm_entry, PAGE_NOERR); - doread = 0; + off_t range_start = start + npages - page_count; + + /* Record the bad pages. */ + if (good_pages != 0) + memset (errors + npages - page_count, ~0, + sizeof (*errors) * page_count); + + memory_object_data_error (control, range_start * vm_page_size, + page_count * vm_page_size, + _pager_page_errors[last_error]); + _pager_mark_object_error (p, range_start, page_count, + _pager_page_errors[last_error]); } /* Let someone else in. */ _pager_release_seqno (p, seqno); mutex_unlock (&p->interlock); - if (!doread) - goto allow_term_out; - if (doerror) - goto error_read; - - err = pager_read_page (p->upi, offset, &page, &write_lock); - if (err) - goto error_read; - - memory_object_data_supply (p->memobjcntl, offset, page, length, 1, - write_lock ? VM_PROT_WRITE : VM_PROT_NONE, 0, - 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; + if (good_pages == npages) + /* All of the pages are good. Optimize the following loop + away. */ + p->ops->read (p, (struct user_pager_info *) &p->upi, start, npages); + else if (good_pages > 0) + { + page_count = 1; + last_error = errors[0]; + + for (i = 1; i < npages; i ++) + { + if (last_error == errors[i]) + page_count ++; + else if (last_error) + /* Already reported the error, just reset the counters. */ + { + page_count = 1; + last_error = 0; + } + else + { + /* Read the pages and give them to the kernel. */ + p->ops->read (p, (struct user_pager_info *) &p->upi, + start + i - page_count, page_count); + + last_error = errors[i]; + } + } + + if (last_error == 0) + p->ops->read (p, (struct user_pager_info *) &p->upi, + start + i - page_count, page_count); + } + else + /* No good data. */ + ; - error_read: - memory_object_data_error (p->memobjcntl, offset, length, EIO); - _pager_mark_object_error (p, offset, length, EIO); - allow_term_out: mutex_lock (&p->interlock); _pager_allow_termination (p); mutex_unlock (&p->interlock); diff --git a/libpager/data-return.c b/libpager/data-return.c index a010c6dc..08255e3d 100644 --- a/libpager/data-return.c +++ b/libpager/data-return.c @@ -21,30 +21,30 @@ #include <string.h> #include <assert.h> -/* Worker function used by _pager_seqnos_memory_object_data_return - and _pager_seqnos_memory_object_data_initialize. All args are - as for _pager_seqnos_memory_object_data_return; the additional - INITIALIZING arg identifies which function is calling us. */ +/* Implement pageout call back as described by <mach/memory_object.defs>. */ kern_return_t -_pager_do_write_request (mach_port_t object, - mach_port_seqno_t seqno, - mach_port_t control, - vm_offset_t offset, - pointer_t data, - vm_size_t length, - int dirty, - int kcopy, - int initializing) +_pager_seqnos_memory_object_data_return (mach_port_t object, + mach_port_seqno_t seqno, + mach_port_t control, + vm_offset_t start_address, + pointer_t data, + vm_size_t length, + int dirty, + int kcopy) { struct pager *p; short *pm_entries; - int npages, i; - error_t *pagerrs; + off_t start; + int npages; + int i; struct lock_request *lr; struct lock_list {struct lock_request *lr; - struct lock_list *next;} *lock_list, *ll; + struct lock_list *next;} *lock_list, *ll; int wakeup; - int omitdata = 0; + + DEBUG ("object = %d, seqno = %d, control = %d, start_address = %d, " + "length = %d, dirty = %d, kcopy", + object, seqno, control, start_address, length, dirty, kcopy); p = ports_lookup_port (0, object, _pager_class); if (!p) @@ -54,18 +54,13 @@ _pager_do_write_request (mach_port_t object, mutex_lock (&p->interlock); _pager_wait_for_seqno (p, seqno); - /* sanity checks -- we don't do multi-page requests yet. */ + /* sanity checks. */ 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); - goto release_out; - } - if (offset % __vm_page_size) + if (start_address % vm_page_size) { printf ("incg data return: misaligned request\n"); goto release_out; @@ -80,15 +75,15 @@ _pager_do_write_request (mach_port_t object, goto release_out; } - npages = length / __vm_page_size; - pagerrs = alloca (npages * sizeof (error_t)); + start = start_address / vm_page_size; + npages = length / vm_page_size; _pager_block_termination (p); /* until we are done with the pagemap when the write completes. */ - _pager_pagemap_resize (p, offset + length); + _pager_pagemap_resize (p, start + length); - pm_entries = &p->pagemap[offset / __vm_page_size]; + pm_entries = &p->pagemap[start]; /* Make sure there are no other in-progress writes for any of these pages before we begin. This imposes a little more serialization @@ -104,35 +99,23 @@ _pager_do_write_request (mach_port_t object, goto retry; } - /* Mark these pages as being paged out. */ - if (initializing) + for (i = 0; i < npages; i++) { - assert (npages <= 32); - for (i = 0; i < npages; i++) - { - if (pm_entries[i] & PM_INIT) - omitdata |= 1 << i; - else - pm_entries[i] |= PM_PAGINGOUT | PM_INIT; - } - } - else - for (i = 0; i < npages; i++) pm_entries[i] |= PM_PAGINGOUT | PM_INIT; - if (!kcopy) - for (i = 0; i < npages; i++) - pm_entries[i] &= ~PM_INCORE; + if (!kcopy) + pm_entries[i] &= ~PM_INCORE; + } /* 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 + 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) + if (start < lr->end && start + npages >= lr->start) { ll = alloca (sizeof (struct lock_list)); ll->lr = lr; @@ -145,50 +128,20 @@ _pager_do_write_request (mach_port_t object, _pager_release_seqno (p, seqno); mutex_unlock (&p->interlock); - /* This is inefficient; we should send all the pages to the device at once - but until the pager library interface is changed, this will have to do. */ - - for (i = 0; i < npages; i++) - if (!(omitdata & (1 << i))) - pagerrs[i] = pager_write_page (p->upi, - offset + (vm_page_size * i), - data + (vm_page_size * i)); + p->ops->write (p, (struct user_pager_info *) &p->upi, start, + npages, (void *) data, 1); /* Acquire the right to meddle with the pagemap */ mutex_lock (&p->interlock); - _pager_pagemap_resize (p, offset + length); - pm_entries = &p->pagemap[offset / __vm_page_size]; + pm_entries = &p->pagemap[start]; wakeup = 0; + for (i = 0; i < npages; i++) { - if (omitdata & (1 << i)) - continue; - if (pm_entries[i] & PM_WRITEWAIT) wakeup = 1; - - if (pagerrs[i] && ! (pm_entries[i] & PM_PAGEINWAIT)) - /* The only thing we can do here is mark the page, and give - errors from now on when it is to be read. This is - imperfect, because if all users go away, the pagemap will - be freed, and this information lost. Oh well. It's still - better than Un*x. Of course, if we are about to hand this - data to the kernel, the error isn't a problem, hence the - check for pageinwait. */ - pm_entries[i] |= PM_INVALID; - - if (pm_entries[i] & PM_PAGEINWAIT) - memory_object_data_supply (p->memobjcntl, - offset + (vm_page_size * i), - data + (vm_page_size * i), - vm_page_size, 1, - VM_PROT_NONE, 0, MACH_PORT_NULL); - else - munmap ((caddr_t) (data + (vm_page_size * i)), - vm_page_size); - - pm_entries[i] &= ~(PM_PAGINGOUT | PM_PAGEINWAIT | PM_WRITEWAIT); + pm_entries[i] &= ~(PM_PAGINGOUT | PM_WRITEWAIT); } for (ll = lock_list; ll; ll = ll->next) @@ -199,9 +152,7 @@ _pager_do_write_request (mach_port_t object, condition_broadcast (&p->wakeup); _pager_allow_termination (p); - mutex_unlock (&p->interlock); - ports_port_deref (p); return 0; @@ -211,18 +162,3 @@ _pager_do_write_request (mach_port_t object, ports_port_deref (p); return 0; } - -/* Implement pageout call back as described by <mach/memory_object.defs>. */ -kern_return_t -_pager_seqnos_memory_object_data_return (mach_port_t object, - mach_port_seqno_t seqno, - mach_port_t control, - vm_offset_t offset, - pointer_t data, - vm_size_t length, - int dirty, - int kcopy) -{ - return _pager_do_write_request (object, seqno, control, offset, data, - length, dirty, kcopy, 0); -} diff --git a/libpager/data-unlock.c b/libpager/data-unlock.c index 9692f589..0bdae18f 100644 --- a/libpager/data-unlock.c +++ b/libpager/data-unlock.c @@ -25,12 +25,11 @@ kern_return_t _pager_seqnos_memory_object_data_unlock (mach_port_t object, mach_port_seqno_t seqno, mach_port_t control, - vm_offset_t offset, + vm_offset_t start, vm_size_t length, vm_prot_t access) { struct pager *p; - volatile int err; p = ports_lookup_port (0, object, _pager_class); if (!p) @@ -58,31 +57,15 @@ _pager_seqnos_memory_object_data_unlock (mach_port_t object, printf ("incg data unlock: not unlock writes\n"); goto out; } - if (offset % __vm_page_size) + if (start % vm_page_size) { printf ("incg data unlock: misaligned request\n"); goto out; } - if (length != __vm_page_size) - { - printf ("incg data unlock: bad length size %zd\n", length); - goto out; - } - err = pager_unlock_page (p->upi, offset); + p->ops->unlock (p, (struct user_pager_info *) &p->upi, + start / vm_page_size, length / vm_page_size); - 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); - 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_mark_next_request_error (p, offset, length, err); - } out: ports_port_deref (p); return 0; diff --git a/libpager/dropweak.c b/libpager/dropweak.c index 54f16b60..9ef61fc5 100644 --- a/libpager/dropweak.c +++ b/libpager/dropweak.c @@ -1,5 +1,5 @@ /* - Copyright (C) 1995 Free Software Foundation, Inc. + Copyright (C) 1995, 2002 Free Software Foundation, Inc. Written by Michael I. Bushnell. This file is part of the GNU Hurd. @@ -25,5 +25,6 @@ _pager_real_dropweak (void *arg) { struct pager *p = arg; - pager_dropweak (p->upi); + if (p->ops->dropweak) + p->ops->dropweak ((struct user_pager_info *) &p->upi); } diff --git a/libpager/get-upi.c b/libpager/get-upi.c index e9e92924..2ee92cc7 100644 --- a/libpager/get-upi.c +++ b/libpager/get-upi.c @@ -23,5 +23,5 @@ struct user_pager_info * pager_get_upi (struct pager *p) { - return p->upi; + return (struct user_pager_info *) &p->upi; } diff --git a/libpager/lock-completed.c b/libpager/lock-completed.c index 1810959f..c6108d59 100644 --- a/libpager/lock-completed.c +++ b/libpager/lock-completed.c @@ -1,5 +1,5 @@ /* Implementation of memory_object_lock_completed for pager library - Copyright (C) 1994, 1995, 1996 Free Software Foundation + Copyright (C) 1994,95,96, 2002 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 @@ -26,12 +26,13 @@ kern_return_t _pager_seqnos_memory_object_lock_completed (mach_port_t object, mach_port_seqno_t seqno, mach_port_t control, - vm_offset_t offset, + vm_offset_t start_address, vm_size_t length) { error_t err = 0; struct pager *p; struct lock_request *lr; + off_t start, npages; p = ports_lookup_port (0, object, _pager_class); if (!p) @@ -49,8 +50,11 @@ _pager_seqnos_memory_object_lock_completed (mach_port_t object, mach_port_deallocate (mach_task_self (), control); + start = start_address / vm_page_size; + npages = length / vm_page_size; + for (lr = p->lock_requests; lr; lr = lr->next) - if (lr->start == offset && lr->end == offset + length) + if (lr->start == start && lr->end == start + npages) { if (lr->locks_pending) --lr->locks_pending; diff --git a/libpager/lock-object.c b/libpager/lock-object.c index d108666e..e9212053 100644 --- a/libpager/lock-object.c +++ b/libpager/lock-object.c @@ -1,5 +1,5 @@ /* Synchronous wrapper for memory_object_lock_request - Copyright (C) 1993, 1994, 1996, 1997, 2000 Free Software Foundation + Copyright (C) 1993,94,96,97, 2000,02 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 @@ -17,14 +17,15 @@ #include "priv.h" -/* 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. */ +/* Request a lock from the kernel on pager P starting at page START + for COUNT pages. Parameters 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. + This must be called with P->interlock help. */ void _pager_lock_object (struct pager *p, - vm_offset_t offset, - vm_size_t size, + off_t start, + off_t count, int should_return, int should_flush, vm_prot_t lock_value, @@ -33,17 +34,13 @@ _pager_lock_object (struct pager *p, int i; struct lock_request *lr = 0; - mutex_lock (&p->interlock); if (p->pager_state != NORMAL) - { - mutex_unlock (&p->interlock); - return; - } + return; if (sync) { for (lr = p->lock_requests; lr; lr = lr->next) - if (lr->start == offset && lr->end == offset + size) + if (lr->start == start && lr->end == start + count) { lr->locks_pending++; lr->threads_waiting++; @@ -52,8 +49,10 @@ _pager_lock_object (struct pager *p, if (!lr) { lr = malloc (sizeof (struct lock_request)); - lr->start = offset; - lr->end = offset + size; + if (! lr) + return; + lr->start = start; + lr->end = start + count; lr->pending_writes = 0; lr->locks_pending = 1; lr->threads_waiting = 1; @@ -65,7 +64,8 @@ _pager_lock_object (struct pager *p, } } - memory_object_lock_request (p->memobjcntl, offset, size, should_return, + memory_object_lock_request (p->memobjcntl, start * vm_page_size, + count * vm_page_size, should_return, should_flush, lock_value, sync ? p->port.port_right : MACH_PORT_NULL); @@ -84,22 +84,14 @@ _pager_lock_object (struct pager *p, if (should_flush) { - vm_offset_t pm_offs = offset / __vm_page_size; + short *pm_entries; - _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; + _pager_pagemap_resize (p, start + count); - if (bound > p->pagemapsize) - bound = p->pagemapsize; + pm_entries = &p->pagemap[start]; - for (i = 0; i < bound; i++) - pm_entries[i] &= ~PM_INCORE; - } + for (i = 0; i < count; i++) + pm_entries[i] &= ~PM_INCORE; } } - - mutex_unlock (&p->interlock); } diff --git a/libpager/mark-error.c b/libpager/mark-error.c index 5c4e029d..dc802832 100644 --- a/libpager/mark-error.c +++ b/libpager/mark-error.c @@ -1,5 +1,5 @@ /* Recording errors for pager library - Copyright (C) 1994, 1997 Free Software Foundation + Copyright (C) 1994, 1997, 2002 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 @@ -20,23 +20,21 @@ int _pager_page_errors[] = {KERN_SUCCESS, ENOSPC, EIO, EDQUOT}; -/* Some error has happened indicating that the page cannot be written. - (Usually this is ENOSPC or EDQOUT.) On the next pagein which - requests write access, return the error to the kernel. (This is +/* Some error has happened indicating that the page cannot be written. + (Usually this is ENOSPC or EDQOUT). On the next pagein which + requests write access, return the error to the kernel. (This is screwy because of the rules associated with m_o_lock_request.) - Currently the only errors permitted are ENOSPC, EIO, and EDQUOT. */ + Currently the only errors permitted are ENOSPC, EIO, and EDQUOT. + PAGER->interlock must be held during this call. */ void _pager_mark_next_request_error(struct pager *pager, - vm_address_t offset, - vm_size_t length, + off_t start, + off_t count, error_t error) { int page_error; short *p; - offset /= __vm_page_size; - length /= __vm_page_size; - switch (error) { case 0: @@ -54,26 +52,25 @@ _pager_mark_next_request_error(struct pager *pager, break; } - for (p = pager->pagemap + offset; p < pager->pagemap + offset + length; p++) + for (p = pager->pagemap + start; p < pager->pagemap + start + count; p++) *p = SET_PM_NEXTERROR (*p, page_error); } -/* We are returning a pager error to the kernel. Write down - in the pager what that error was so that the exception handling - routines can find out. (This is only necessary because the - XP interface is not completely implemented in the kernel.) - Again, only ENOSPC, EIO, and EDQUOT are permitted. */ +/* We are returning a pager error to the kernel. Write down in the + pager what that error was so that the exception handling routines + can find out. (This is only necessary because the XP interface is + not completely implemented in the kernel.) Again, only ENOSPC, + EIO, and EDQUOT are permitted. PAGER->interlock must be held + during this call. _pager_pagemap_resize should have been + called. */ void _pager_mark_object_error(struct pager *pager, - vm_address_t offset, - vm_size_t length, + off_t start, + off_t count, error_t error) { int page_error = 0; short *p; - - offset /= __vm_page_size; - length /= __vm_page_size; switch (error) { @@ -92,29 +89,27 @@ _pager_mark_object_error(struct pager *pager, break; } - for (p = pager->pagemap + offset; p < pager->pagemap + offset + length; p++) + for (p = pager->pagemap + start; p < pager->pagemap + start + count; p++) *p = SET_PM_ERROR (*p, page_error); } /* Tell us what the error (set with mark_object_error) for - pager P is on page ADDR. */ + pager P is on page PAGE. */ error_t -pager_get_error (struct pager *p, vm_address_t addr) +pager_get_error (struct pager *p, off_t page) { error_t err; mutex_lock (&p->interlock); - addr /= vm_page_size; - - /* If there really is no error for ADDR, we should be able to exted the + /* If there really is no error for PAGE, we should be able to extend the pagemap table; otherwise, if some previous operation failed because it couldn't extend the table, this attempt will *probably* (heh) fail for the same reason. */ - err = _pager_pagemap_resize (p, addr); + err = _pager_pagemap_resize (p, page); if (! err) - err = _pager_page_errors[PM_ERROR(p->pagemap[addr])]; + err = _pager_page_errors[PM_ERROR(p->pagemap[page])]; mutex_unlock (&p->interlock); diff --git a/libpager/object-init.c b/libpager/object-init.c index eeb50993..1fb882f0 100644 --- a/libpager/object-init.c +++ b/libpager/object-init.c @@ -1,5 +1,5 @@ /* Implementation of memory_object_init for pager library - Copyright (C) 1994, 1995, 1996 Free Software Foundation + Copyright (C) 1994,95,96,2001 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 @@ -37,7 +37,7 @@ _pager_seqnos_memory_object_init (mach_port_t object, mutex_lock (&p->interlock); _pager_wait_for_seqno (p, seqno); - if (pagesize != __vm_page_size) + if (pagesize != vm_page_size) { printf ("incg init: bad page size"); goto out; @@ -47,6 +47,9 @@ _pager_seqnos_memory_object_init (mach_port_t object, { #ifdef KERNEL_INIT_RACE struct pending_init *i = malloc (sizeof (struct pending_init)); + if (! i) + goto out; + printf ("pager out-of-sequence init\n"); i->control = control; i->name = name; diff --git a/libpager/offer-page.c b/libpager/offer-page.c deleted file mode 100644 index aed22197..00000000 --- a/libpager/offer-page.c +++ /dev/null @@ -1,52 +0,0 @@ -/* Wrapper for unsolicited memory_object_data_supply - Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc. - Written by Michael I. Bushnell, p/BSG. - - This file is part of the GNU Hurd. - - The GNU Hurd 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. - - The GNU Hurd 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ - - -#include "priv.h" - -void -pager_offer_page (struct pager *p, - int precious, - int writelock, - vm_offset_t offset, - vm_address_t buf) -{ - mutex_lock (&p->interlock); - - if (_pager_pagemap_resize (p, offset + vm_page_size)) - { - short *pm_entry = &p->pagemap[offset / vm_page_size]; - - while (*pm_entry & PM_INCORE) - { - mutex_unlock (&p->interlock); - pager_flush_some (p, offset, vm_page_size, 1); - mutex_lock (&p->interlock); - } - *pm_entry |= PM_INCORE; - - memory_object_data_supply (p->memobjcntl, offset, buf, vm_page_size, 0, - writelock ? VM_PROT_WRITE : VM_PROT_NONE, - precious, MACH_PORT_NULL); - } - - mutex_unlock (&p->interlock); -} - diff --git a/libpager/pagemap.c b/libpager/pagemap.c index b8b3362c..060563f7 100644 --- a/libpager/pagemap.c +++ b/libpager/pagemap.c @@ -1,5 +1,5 @@ /* Pagemap manipulation for pager library - Copyright (C) 1994, 1997, 1999, 2000 Free Software Foundation + Copyright (C) 1994,97,99,2000,02 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 @@ -17,29 +17,51 @@ #include "priv.h" #include <string.h> +#include <assert.h> + +/* Start using vm_copy over memcpy when we have at least two + pages. */ +#define VMCOPY_BETTER_THAN_MEMCPY (vm_page_size * 2) -/* Grow the pagemap of pager P as necessary to deal with address OFF */ +/* Grow the pagemap of pager P as necessary to deal with page address + OFF - 1. */ error_t -_pager_pagemap_resize (struct pager *p, vm_address_t off) +_pager_pagemap_resize (struct pager *p, off_t off) { error_t err = 0; - - off /= __vm_page_size; - if (p->pagemapsize < off) + assert (((p->pagemapsize * sizeof (*p->pagemap)) + & (vm_page_size - 1)) == 0); + + if (p->pagemapsize <= off) { void *newaddr; - int newsize = round_page (off); + int newsize = round_page (off * sizeof (*p->pagemap)); - newaddr = mmap (0, newsize * sizeof (*p->pagemap), - PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); - err = (newaddr == (void *) -1) ? errno : 0; - if (! err) + newaddr = mmap (0, newsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + if (newaddr == MAP_FAILED) + err = errno; + else { - bcopy (p->pagemap, newaddr, p->pagemapsize * sizeof (*p->pagemap)); - munmap (p->pagemap, p->pagemapsize * sizeof (*p->pagemap)); + int oldsize = p->pagemapsize * sizeof (*p->pagemap); + + if (oldsize > 0) + { + if (oldsize >= VMCOPY_BETTER_THAN_MEMCPY) + { + err = vm_copy (mach_task_self (), + (vm_address_t) p->pagemap, oldsize, + (vm_address_t) newaddr); + assert_perror (err); + } + else + memcpy (newaddr, p->pagemap, oldsize); + + munmap (p->pagemap, oldsize); + } + p->pagemap = newaddr; - p->pagemapsize = newsize; + p->pagemapsize = newsize / sizeof (*p->pagemap); } } diff --git a/libpager/pager-attr.c b/libpager/pager-attr.c index cbc1533f..adf62ae4 100644 --- a/libpager/pager-attr.c +++ b/libpager/pager-attr.c @@ -21,7 +21,7 @@ /* Change the attributes of the memory object underlying pager P. Args MAY_CACHE and COPY_STRATEGY are as for memory_object_change_atributes. Wait for the kernel to report completion - off WAIT is set.*/ + if WAIT is set.*/ void pager_change_attributes (struct pager *p, boolean_t may_cache, @@ -65,6 +65,7 @@ pager_change_attributes (struct pager *p, if (!ar) { ar = malloc (sizeof (struct attribute_request)); + assert (ar); ar->may_cache = may_cache; ar->copy_strategy = copy_strategy; ar->attrs_pending = 1; diff --git a/libpager/pager-create.c b/libpager/pager-create.c index 26d1aad2..f23ddf3d 100644 --- a/libpager/pager-create.c +++ b/libpager/pager-create.c @@ -1,5 +1,5 @@ /* Pager creation - Copyright (C) 1994, 1995, 1996 Free Software Foundation + Copyright (C) 1994,95,96,2001,02 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 @@ -19,18 +19,21 @@ /* Create and return a new pager with user info UPI. */ struct pager * -pager_create (struct user_pager_info *upi, +pager_create (struct pager_ops *ops, + size_t upi_size, struct port_bucket *bucket, boolean_t may_cache, memory_object_copy_strategy_t copy_strategy) { + error_t err; struct pager *p; - errno = ports_create_port (_pager_class, bucket, sizeof (struct pager), &p); - if (errno) + err = ports_create_port (_pager_class, bucket, + sizeof (struct pager) + upi_size, &p); + if (err) return 0; - p->upi = upi; + p->ops = ops; p->pager_state = NOTINIT; mutex_init (&p->interlock); condition_init (&p->wakeup); diff --git a/libpager/pager-data-read-error.c b/libpager/pager-data-read-error.c new file mode 100644 index 00000000..ecd5204d --- /dev/null +++ b/libpager/pager-data-read-error.c @@ -0,0 +1,36 @@ +/* Indicate an error reading data. + Copyright (C) 2002 Free Software Foundation, Inc. + Written by Neal H Walfield + + This file is part of the GNU Hurd. + + The GNU Hurd 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. + + The GNU Hurd 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + + +#include "priv.h" + +void +pager_data_read_error (struct pager *pager, + off_t start, off_t npages, + error_t err) +{ + memory_object_data_error (pager->memobjcntl, start * vm_page_size, + npages * vm_page_size, err); + + mutex_lock (&pager->interlock); + _pager_pagemap_resize (pager, start + npages); + _pager_mark_object_error (pager, start, npages, err); + mutex_unlock (&pager->interlock); +} diff --git a/libpager/pager-data-supply.c b/libpager/pager-data-supply.c new file mode 100644 index 00000000..7a91ea3f --- /dev/null +++ b/libpager/pager-data-supply.c @@ -0,0 +1,41 @@ +/* Supply data to the kernel. + Copyright (C) 2002 Free Software Foundation, Inc. + Written by Neal H Walfield + + This file is part of the GNU Hurd. + + The GNU Hurd 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. + + The GNU Hurd 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + + +#include "priv.h" + +void +pager_data_supply (struct pager *pager, + int precious, int readonly, + off_t start, off_t npages, + void *buf, int dealloc) +{ + memory_object_data_supply (pager->memobjcntl, start * vm_page_size, + (vm_address_t) buf, npages * vm_page_size, + dealloc, + readonly ? VM_PROT_WRITE : VM_PROT_NONE, + precious, MACH_PORT_NULL); + + mutex_lock (&pager->interlock); + _pager_pagemap_resize (pager, start + npages); + _pager_mark_object_error (pager, start, npages, 0); + mutex_unlock (&pager->interlock); + +} diff --git a/libpager/pager-data-unavailable.c b/libpager/pager-data-unavailable.c new file mode 100644 index 00000000..05e1ed1b --- /dev/null +++ b/libpager/pager-data-unavailable.c @@ -0,0 +1,36 @@ +/* Indicate that there is no allocated data for a given range. + Copyright (C) 2002 Free Software Foundation, Inc. + Written by Neal H Walfield. + + This file is part of the GNU Hurd. + + The GNU Hurd 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. + + The GNU Hurd 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + + +#include "priv.h" + +void +pager_data_unavailable (struct pager *pager, + off_t start, off_t npages) +{ + memory_object_data_unavailable (pager->memobjcntl, + start * vm_page_size, + npages * vm_page_size); + + mutex_lock (&pager->interlock); + _pager_pagemap_resize (pager, start + npages); + _pager_mark_object_error (pager, start, npages, 0); + mutex_unlock (&pager->interlock); +} diff --git a/libpager/pager-data-unlock-error.c b/libpager/pager-data-unlock-error.c new file mode 100644 index 00000000..1b568a87 --- /dev/null +++ b/libpager/pager-data-unlock-error.c @@ -0,0 +1,41 @@ +/* Indicate an error unlocking some pages. + Copyright (C) 2002 Free Software Foundation, Inc. + Written by Neal H Walfield + + This file is part of the GNU Hurd. + + The GNU Hurd 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. + + The GNU Hurd 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + + +#include "priv.h" + +void +pager_data_unlock_error (struct pager *pager, + off_t start, off_t npages, + error_t err) +{ + mutex_lock (&pager->interlock); + + /* Flush the range and set a bit so that + m_o_data_request knows to issue an error. */ + _pager_lock_object (pager, start, npages, + MEMORY_OBJECT_RETURN_NONE, 1, + VM_PROT_WRITE, 1); + + _pager_pagemap_resize (pager, start + npages); + _pager_mark_next_request_error (pager, start, npages, err); + + mutex_unlock (&pager->interlock); +} diff --git a/libpager/pager-data-unlock.c b/libpager/pager-data-unlock.c new file mode 100644 index 00000000..f76f7aa5 --- /dev/null +++ b/libpager/pager-data-unlock.c @@ -0,0 +1,33 @@ +/* Mark pages as writable. + Copyright (C) 2002 Free Software Foundation, Inc. + Written by Neal H Walfield + + This file is part of the GNU Hurd. + + The GNU Hurd 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. + + The GNU Hurd 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + + +#include "priv.h" + +void +pager_data_unlock (struct pager *pager, + off_t start, off_t count) +{ + mutex_lock (&pager->interlock); + _pager_lock_object (pager, start, count, + MEMORY_OBJECT_RETURN_NONE, 0, + VM_PROT_NONE, 0); + mutex_unlock (&pager->interlock); +} diff --git a/libpager/pager-data-write-error.c b/libpager/pager-data-write-error.c new file mode 100644 index 00000000..b5806509 --- /dev/null +++ b/libpager/pager-data-write-error.c @@ -0,0 +1,44 @@ +/* Indicate an error while writing data. + Copyright (C) 2002 Free Software Foundation, Inc. + Written by Neal H Walfield + + This file is part of the GNU Hurd. + + The GNU Hurd 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. + + The GNU Hurd 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + + +#include "priv.h" + +void +pager_data_write_error (struct pager *pager, + off_t start, off_t npages, + error_t err) +{ + int i; + short *pm_entries; + + memory_object_data_error (pager->memobjcntl, start * vm_page_size, + npages * vm_page_size, err); + + mutex_lock (&pager->interlock); + _pager_pagemap_resize (pager, start + npages); + _pager_mark_object_error (pager, start, npages, err); + + pm_entries = &pager->pagemap[start]; + for (i = 0; i < npages; i ++) + pm_entries[i] |= PM_INVALID; + + mutex_unlock (&pager->interlock); +} diff --git a/libpager/pager-flush.c b/libpager/pager-flush.c index 55a76de6..d03da144 100644 --- a/libpager/pager-flush.c +++ b/libpager/pager-flush.c @@ -1,5 +1,5 @@ /* Functions for flushing data - Copyright (C) 1994, 1996 Free Software Foundation + Copyright (C) 1994,96,2002 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 @@ -22,24 +22,24 @@ void pager_flush (struct pager *p, int wait) { - vm_address_t offset; - vm_size_t len; - - pager_report_extent (p->upi, &offset, &len); - - _pager_lock_object (p, offset, len, MEMORY_OBJECT_RETURN_NONE, 1, - VM_PROT_NO_CHANGE, wait); + off_t start, end; + + p->ops->report_extent ((struct user_pager_info *) p->upi, &start, &end); + + pager_flush_some (p, start, end - start, wait); } -/* Have the kernel write back some pages of a pager from OFFSET to - OFFSET+SIZE; if WAIT is set, then wait for them to be finally +/* Have the kernel write back some pages of a pager from START to + START+COUNT; if WAIT is set, then wait for them to be finally written before returning. */ void -pager_flush_some (struct pager *p, vm_address_t offset, - vm_size_t size, int wait) +pager_flush_some (struct pager *p, off_t start, + off_t count, int wait) { - _pager_lock_object (p, offset, size, MEMORY_OBJECT_RETURN_NONE, 1, + mutex_lock (&p->interlock); + _pager_lock_object (p, start, count, MEMORY_OBJECT_RETURN_NONE, 1, VM_PROT_NO_CHANGE, wait); + mutex_unlock (&p->interlock); } diff --git a/libpager/pager-memcpy.c b/libpager/pager-memcpy.c index f2be5585..08f676b6 100644 --- a/libpager/pager-memcpy.c +++ b/libpager/pager-memcpy.c @@ -37,7 +37,7 @@ if there is no fault, returns 0 and *SIZE will be unchanged. */ error_t pager_memcpy (struct pager *pager, memory_object_t memobj, - vm_offset_t offset, void *other, size_t *size, + off_t offset, void *other, size_t *size, vm_prot_t prot) { error_t err; diff --git a/libpager/pager-return.c b/libpager/pager-return.c index b1013059..110821be 100644 --- a/libpager/pager-return.c +++ b/libpager/pager-return.c @@ -1,5 +1,5 @@ /* - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996, 2002 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -25,20 +25,19 @@ void pager_return (struct pager *p, int wait) { - vm_address_t offset; - vm_size_t len; - - pager_report_extent (p->upi, &offset, &len); - - _pager_lock_object (p, offset, len, MEMORY_OBJECT_RETURN_ALL, 1, - VM_PROT_NO_CHANGE, wait); + off_t start, end; + + p->ops->report_extent ((struct user_pager_info *) &p->upi, &start, &end); + + pager_return_some (p, start, end - start, wait); } void -pager_return_some (struct pager *p, vm_address_t offset, - vm_size_t size, int wait) +pager_return_some (struct pager *p, off_t start, off_t count, int wait) { - _pager_lock_object (p, offset, size, MEMORY_OBJECT_RETURN_ALL, 1, + mutex_lock (&p->interlock); + _pager_lock_object (p, start, count, MEMORY_OBJECT_RETURN_ALL, 1, VM_PROT_NO_CHANGE, wait); + mutex_unlock (&p->interlock); } diff --git a/libpager/pager-sync.c b/libpager/pager-sync.c index d98a3ac8..d5eb4ef8 100644 --- a/libpager/pager-sync.c +++ b/libpager/pager-sync.c @@ -1,5 +1,5 @@ /* Functions for sync. - Copyright (C) 1994, 1996 Free Software Foundation + Copyright (C) 1994, 1996, 2002 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 @@ -23,23 +23,21 @@ void pager_sync (struct pager *p, int wait) { - vm_address_t offset; - vm_size_t len; + off_t start, end; - pager_report_extent (p->upi, &offset, &len); - - _pager_lock_object (p, offset, len, MEMORY_OBJECT_RETURN_ALL, 0, - VM_PROT_NO_CHANGE, wait); -} + p->ops->report_extent ((struct user_pager_info *) p->upi, &start, &end); + pager_sync_some (p, start, end - start, wait); +} /* Have the kernel write back some pages of a pager; if WAIT is set, then wait for them to be finally written before returning. */ void -pager_sync_some (struct pager *p, vm_address_t offset, - vm_size_t size, int wait) +pager_sync_some (struct pager *p, off_t start, off_t count, + int wait) { - _pager_lock_object (p, offset, size, MEMORY_OBJECT_RETURN_ALL, 0, + mutex_lock (&p->interlock); + _pager_lock_object (p, start, count, MEMORY_OBJECT_RETURN_ALL, 0, VM_PROT_NO_CHANGE, wait); + mutex_unlock (&p->interlock); } - diff --git a/libpager/pager.h b/libpager/pager.h index 99fb3845..1f73078a 100644 --- a/libpager/pager.h +++ b/libpager/pager.h @@ -1,5 +1,5 @@ /* Definitions for multi-threaded pager library - Copyright (C) 1994, 1995, 1996, 1997, 1999 Free Software Foundation, Inc. + Copyright (C) 1994,95,96,97,99, 2002 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -21,47 +21,113 @@ #include <hurd/ports.h> -/* This declaration exists to place struct user_pager_info in the proper - scope. */ +/* These declarations exists to place struct user_pager_info and + struct pager in the proper scope. */ struct user_pager_info; +struct pager; +struct pager_ops +{ + /* Read from PAGER's backing store, starting at page START, NPAGES + pages. + + The data is to be provided using either pager_data_supply or + pager_data_unavailable. + + If an error is encountered reading any pages, it is to be + reported using pager_data_read_error. + + For each indicated page, the callee *must* call exactly one of + the above methods; the pager library will not rerequest + pages. */ + void (*read)(struct pager *pager, struct user_pager_info *upi, + off_t start, off_t npages); + + /* Synchronously write to PAGER's backing store the NPAGES pages + pointed to be BUF starting at page START. + + If DEALLOC is set, BUF must be deallocate be the callee. + + If an error is encountered while writing the pages to the backing + store, it must be reported using pager_data_write_error. */ + void (*write)(struct pager *pager, struct user_pager_info *upi, + off_t start, off_t npages, void *buf, int dealloc); + + /* The NPAGES pages, starting at page START, should be made writable. + + Success is to be indicated using pager_data_unlock; errors using + pager_data_unlock_error. */ + void (*unlock)(struct pager *pager, struct user_pager_info *upi, + off_t start, off_t npages); + + /* Report the first (normally zero) and last valid pages that the + pager will accept and store them in START and *END + respectively. */ + void (*report_extent)(struct user_pager_info *upi, + off_t *start, off_t *end); + + /* The user may define this function. If non-NULL, it is called + when a pager is being deallocated after all extant send rights + have been destroyed. */ + void (*clear_user_data)(struct user_pager_info *upi); + + /* This is called when the ports library wants to drop weak + references. The pager library creates no weak references itself. + If the user doesn't either, then it's OK for this function to do + nothing or be set to NULL. */ + void (*dropweak)(struct user_pager_info *upi); +}; + /* This de-muxer function is for use within libports_demuxer. */ /* INP is a message we've received; OUTP will be filled in with a reply message. */ int pager_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp); -/* Create a new pager. The pager will have a port created for it - (using libports, in BUCKET) and will be immediately ready - to receive requests. U_PAGER will be provided to later calls to - pager_find_address. The pager will have one user reference - created. MAY_CACHE and COPY_STRATEGY are the original values of - those attributes as for memory_object_ready. Users may create - references to pagers by use of the relevant ports library - functions. On errors, return null and set errno. */ +/* Create a new pager. The pager will have a port created for it (using + libports, in BUCKET), but associated with the OPS operation structure + and will be immediately ready to receive requests. The pager will + have one user reference created. MAY_CACHE and COPY_STRATEGY are the + original values of those attributes as for memory_object_ready. + Users may create references to pagers by use of the relevant ports + library functions. A block of memory of size UPI_SIZE for pager state + will be allocated and provided to the call back functions or via + pager_get_upi. On errors, null is returned and sets errno is set. */ struct pager * -pager_create (struct user_pager_info *u_pager, +pager_create (struct pager_ops *ops, + size_t upi_size, struct port_bucket *bucket, boolean_t may_cache, memory_object_copy_strategy_t copy_strategy); /* Return the user_pager_info struct associated with a pager. */ struct user_pager_info * -pager_get_upi (struct pager *p); +pager_get_upi (struct pager *pager); +/* Return the port (receive right) for requests to the pager. It is + absolutely necessary that a new send right be created from this + receive right. */ +mach_port_t +pager_get_port (struct pager *pager); + +/* Return the error code of the last page error for pager PAGER at + page PAGE; this will be deleted when the kernel interface is + fixed. */ +error_t +pager_get_error (struct pager *pager, off_t page); + /* Sync data from pager PAGER to backing store; wait for all the writes to complete iff WAIT is set. */ void pager_sync (struct pager *pager, int wait); -/* Sync some data (starting at START, for LEN bytes) from pager PAGER - to backing store. Wait for all the writes to complete iff WAIT is - set. */ +/* Sync some data (starting at page START, for NPAGES pages) from pager + PAGER to backing store. Wait for all the writes to complete iff + WAIT is set. */ void pager_sync_some (struct pager *pager, - vm_address_t start, - vm_size_t len, + off_t start, off_t npages, int wait); /* Flush data from the kernel for pager PAGER and force any pending @@ -70,13 +136,12 @@ void pager_flush (struct pager *pager, int wait); - -/* Flush some data (starting at START, for LEN bytes) for pager PAGER - from the kernel. Wait for all pages to be flushed iff WAIT is set. */ +/* Flush some data (starting at page START, for NPAGES pages) for pager + PAGER from the kernel. Wait for all pages to be flushed iff WAIT + is set. */ void pager_flush_some (struct pager *pager, - vm_address_t start, - vm_size_t len, + off_t start, off_t npages, int wait); /* Flush data from the kernel for pager PAGER and force any pending @@ -86,43 +151,99 @@ void pager_return (struct pager *pager, int wait); - -/* Flush some data (starting at START, for LEN bytes) for pager PAGER - from the kernel. Wait for all pages to be flushed iff WAIT is set. - Have the kernel write back modifications. */ +/* Flush some data (starting at page START, for NPAGES pages) for pager + PAGER from the kernel. Wait for all pages to be flushed iff WAIT + is set. Have the kernel write back modifications. */ void pager_return_some (struct pager *pager, - vm_address_t start, - vm_size_t len, + off_t start, off_t npages, int wait); + +/* Offer the NPAGES pages from BUF to the kernel for pager PAGER + starting at page START. If PRECIOUS is set, then the pages will be + paged out at some future point, otherwise they may be dropped with + out notice. IF READONLY is set, this data will be provided read + only to the kernel. In this case, any attempts to write to the + pages will cause the PAGER->UNLOCK method to be called. If DEALLOC + is set, the buffer pointed to by BUF will be deallocated. + + NB: If the data is currently in core, the kernel may ignore this + call. As such, pager_flush_some should be called if the call was + not in response to a PAGER->READ event. + + This function is normally called as a response to the PAGER->READ + method. */ +void +pager_data_supply (struct pager *pager, + int precious, int readonly, + off_t start, off_t npages, + void *buf, int dealloc); + +/* Indicate to the kernel that the NPAGES pages starting at START are + unavailable and should be supplied as anonymous (i.e. zero) + pages. + + This function is normally only called in response to the + PAGER->READ method. */ +void +pager_data_unavailable (struct pager *pager, + off_t start, off_t npages); + +/* Indicate that an error has occured while trying to read the NPAGES + pages starting at page START from pager PAGER's backing store. The + only permissable values for ERROR are: EIO, EDQUOT, and ENOSPC (all + others will be ignored and squashed to EIO). -/* Offer a page of data to the kernel. If PRECIOUS is set, then this - page will be paged out at some future point, otherwise it might be - dropped by the kernel. If the page is currently in core, the - kernel might ignore this call. */ + This is normally only called in response to the PAGER->READ + method. */ void -pager_offer_page (struct pager *pager, - int precious, - int writelock, - vm_offset_t page, - vm_address_t buf); +pager_data_read_error (struct pager *pager, + off_t start, off_t npages, + error_t error); +/* Indicate that an error has occured while trying to write the NPAGES + pages starting at page START to pager PAGER's backing store. The + only permissable values for ERROR are: EIO, EDQUOT, and ENOSPC (all + others will be ignored and squashed to EIO). + + This is normally only called in response to the PAGER->WRITE + method. */ +void +pager_data_write_error (struct pager *pager, + off_t start, off_t npages, + error_t error); + +/* Indicate that the NPAGES pages starting at page START in pager PAGER + have been made writable. + + This is normally only called in response to the PAGER->UNLOCK + method. */ +void +pager_data_unlock (struct pager *pager, + off_t start, off_t npages); + +/* Indicate that an error has occured unlocking (i.e. making writable) + the NPAGES pages starting at page START in pager PAGER. The only + permissable values for ERROR are: EIO, EDQUOT, and ENOSPC (all + others will be ignored and squashed to EIO). + + This is normally only called in response to the PAGER->UNLOCK + method. */ +void +pager_data_unlock_error (struct pager *pager, + off_t start, off_t npages, + error_t error); + /* Change the attributes of the memory object underlying pager PAGER. Args MAY_CACHE and COPY_STRATEGY are as for - memory_object_change_atributes. Wait for the kernel to report completion - off WAIT is set.*/ + memory_object_change_attributes. Wait for the kernel to report + completion if WAIT is set.*/ void pager_change_attributes (struct pager *pager, boolean_t may_cache, memory_object_copy_strategy_t copy_strategy, int wait); -/* Return the port (receive right) for requests to the pager. It is - absolutely necessary that a new send right be created from this - receive right. */ -mach_port_t -pager_get_port (struct pager *pager); - /* Force termination of a pager. After this returns, no more paging requests on the pager will be honored, and the pager will be deallocated. (The actual deallocation might @@ -131,65 +252,16 @@ pager_get_port (struct pager *pager); void pager_shutdown (struct pager *pager); -/* Return the error code of the last page error for pager P at address ADDR; - this will be deleted when the kernel interface is fixed. */ -error_t -pager_get_error (struct pager *p, vm_address_t addr); - -/* Try to copy *SIZE bytes between the region OTHER points to - and the region at OFFSET in the pager indicated by PAGER and MEMOBJ. - If PROT is VM_PROT_READ, copying is from the pager to OTHER; - if PROT contains VM_PROT_WRITE, copying is from OTHER into the pager. - *SIZE is always filled in the actual number of bytes successfully copied. - Returns an error code if the pager-backed memory faults; +/* Try to copy *SIZE bytes between the region OTHER points to and the + region at byte OFFSET in the pager indicated by PAGER and MEMOBJ. + If PROT is VM_PROT_READ, copying is from the pager to OTHER; if + PROT contains VM_PROT_WRITE, copying is from OTHER into the pager. + *SIZE is always filled in the actual number of bytes successfully + copied. Returns an error code if the pager-backed memory faults; if there is no fault, returns 0 and *SIZE will be unchanged. */ error_t pager_memcpy (struct pager *pager, memory_object_t memobj, - vm_offset_t offset, void *other, size_t *size, + off_t offset, void *other, size_t *size, vm_prot_t prot); -/* The user must define this function. For pager PAGER, read one - page from offset PAGE. Set *BUF to be the address of the page, - and set *WRITE_LOCK if the page must be provided read-only. - The only permissible error returns are EIO, EDQUOT, and ENOSPC. */ -error_t -pager_read_page (struct user_pager_info *pager, - vm_offset_t page, - vm_address_t *buf, - int *write_lock); - -/* The user must define this function. For pager PAGER, synchronously - write one page from BUF to offset PAGE. In addition, mfree - (or equivalent) BUF. The only permissible error returns are EIO, - EDQUOT, and ENOSPC. */ -error_t -pager_write_page (struct user_pager_info *pager, - vm_offset_t page, - vm_address_t buf); - -/* The user must define this function. A page should be made writable. */ -error_t -pager_unlock_page (struct user_pager_info *pager, - vm_offset_t address); - -/* The user must define this function. It should report back (in - *OFFSET and *SIZE the minimum valid address the pager will accept - and the size of the object. */ -error_t -pager_report_extent (struct user_pager_info *pager, - vm_address_t *offset, - vm_size_t *size); - -/* The user must define this function. This is called when a pager is - being deallocated after all extant send rights have been destroyed. */ -void -pager_clear_user_data (struct user_pager_info *pager); - -/* The use must define this function. This will be called when the ports - library wants to drop weak references. The pager library creates no - weak references itself. If the user doesn't either, then it's OK for - this function to do nothing. */ -void -pager_dropweak (struct user_pager_info *p); - #endif diff --git a/libpager/priv.h b/libpager/priv.h index 586bccbf..e7665d3e 100644 --- a/libpager/priv.h +++ b/libpager/priv.h @@ -1,5 +1,5 @@ /* Private data for pager library. - Copyright (C) 1994-1997, 1999, 2000, 2011 Free Software Foundation, Inc. + Copyright (C) 1994-1997, 1999, 2000,02,11 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -21,6 +21,13 @@ #include "pager.h" #include <hurd/ports.h> +#if 0 +#include <stdio.h> +#define DEBUG(fmt, args...) printf (__FUNCTION__ ": " fmt "\n" , ## args) +#else +#define DEBUG(fmt, args...) +#endif + /* Define this if you think the kernel is sending memory_object_init out of sequence with memory_object_terminate. */ /* #undef KERNEL_INIT_RACE */ @@ -28,7 +35,8 @@ struct pager { struct port_info port; - struct user_pager_info *upi; + + struct pager_ops *ops; enum { @@ -67,6 +75,8 @@ struct pager short *pagemap; int pagemapsize; /* number of elements in PAGEMAP */ + + char upi[0]; }; struct lock_request @@ -108,11 +118,10 @@ extern int _pager_page_errors[]; /* Pagemap format */ /* These are binary state bits */ -#define PM_WRITEWAIT 0x0200 /* queue wakeup once write is done */ -#define PM_INIT 0x0100 /* data has been written */ -#define PM_INCORE 0x0080 /* kernel might have a copy */ -#define PM_PAGINGOUT 0x0040 /* being written to disk */ -#define PM_PAGEINWAIT 0x0020 /* provide data back when write done */ +#define PM_WRITEWAIT 0x0100 /* queue wakeup once write is done */ +#define PM_INIT 0x0080 /* data has been written */ +#define PM_INCORE 0x0040 /* kernel might have a copy */ +#define PM_PAGINGOUT 0x0020 /* being written to disk */ #define PM_INVALID 0x0010 /* data on disk is irrevocably wrong */ /* These take values of enum page_errors */ @@ -136,12 +145,10 @@ void _pager_release_seqno (struct pager *, mach_port_seqno_t); void _pager_update_seqno (mach_port_t, mach_port_seqno_t); 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, +error_t _pager_pagemap_resize (struct pager *, off_t); +void _pager_mark_next_request_error (struct pager *, off_t, off_t, error_t); +void _pager_mark_object_error (struct pager *, off_t, off_t, error_t); +void _pager_lock_object (struct pager *, off_t, off_t, int, int, vm_prot_t, int); void _pager_free_structure (struct pager *); void _pager_clean (void *arg); |