From 0e847864cef404f555387d7fcc97f7dbe769e1e9 Mon Sep 17 00:00:00 2001 From: Richard Braun Date: Fri, 3 May 2013 19:56:50 +0200 Subject: Handle notification on page eviction If requested by the user, make libpager call pager_notify_evict when a page is flushed out by the kernel. Based on work by Ognyan Kulev. * console/pager.c (pager_notify_evict): New function. (user_pager_create): Update call to pager_create. * ext2fs/pager.c: (pager_notify_evict): New function. (create_disk_pager): Update call to diskfs_start_disk_pager. (diskfs_get_filemap): Update call to pager_create. * fatfs/pager.c: (pager_notify_evict): New function. (create_fat_pager): Update call to diskfs_start_disk_pager. (diskfs_get_filemap): Update call to pager_create. * isofs/pager.c: (pager_notify_evict): New function. (create_disk_pager): Update call to diskfs_start_disk_pager. (diskfs_get_filemap): Update call to pager_create. * libdiskfs/disk-pager.c (diskfs_start_disk_pager): Update definition and call to pager_create. * libdiskfs/diskfs-pager.h (diskfs_start_disk_pager): Update declaration. * libpager/data-request.c (_pager_seqnos_memory_object_data_request): Take pager's `notify_on_evict' member into account when calling memory_object_data_supply. * libpager/data-return.c (_pager_do_write_request): Handle user notification on page flush. * libpager/pager-create.c (pager_create): Update definition and set pager's `notify_on_evict' member. * libpager/pager.h (pager_create): Update declaration. (pager_notify_evict): New declaration. * libpager/priv.h (struct pager): New `notify_on_evict' member. * storeio/pager.c: (pager_notify_evict): New function. (dev_get_memory_object): Update call to pager_create. * tmpfs/pager-stubs.c (pager_notify_evict): New function. * ufs/pager.c (pager_notify_evict): New function. (create_disk_pager): Update call to diskfs_start_disk_pager. (diskfs_get_filemap): Update call to pager_create. --- libpager/data-return.c | 79 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 16 deletions(-) (limited to 'libpager/data-return.c') diff --git a/libpager/data-return.c b/libpager/data-return.c index c70f0e8d..6a3b9037 100644 --- a/libpager/data-return.c +++ b/libpager/data-return.c @@ -39,6 +39,7 @@ _pager_do_write_request (mach_port_t object, struct pager *p; short *pm_entries; int npages, i; + char *notified; error_t *pagerrs; struct lock_request *lr; struct lock_list {struct lock_request *lr; @@ -71,9 +72,6 @@ _pager_do_write_request (mach_port_t object, goto release_out; } - if (! dirty) - goto release_out; - if (p->pager_state != NORMAL) { printf ("pager in wrong state for write\n"); @@ -83,6 +81,11 @@ _pager_do_write_request (mach_port_t object, npages = length / __vm_page_size; pagerrs = alloca (npages * sizeof (error_t)); + notified = alloca (npages * (sizeof *notified)); +#ifndef NDEBUG + memset (notified, -1, npages * (sizeof *notified)); +#endif + _pager_block_termination (p); /* until we are done with the pagemap when the write completes. */ @@ -90,6 +93,24 @@ _pager_do_write_request (mach_port_t object, pm_entries = &p->pagemap[offset / __vm_page_size]; + if (! dirty) + { + munmap ((void *) data, length); + if (!kcopy) { + /* Prepare notified array. */ + for (i = 0; i < npages; i++) + notified[i] = (p->notify_on_evict + && ! (pm_entries[i] & PM_PAGEINWAIT)); + + _pager_release_seqno (p, seqno); + goto notify; + } + else { + _pager_allow_termination (p); + 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 than we really have to require (because *all* future writes on @@ -120,10 +141,6 @@ _pager_do_write_request (mach_port_t object, 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 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 @@ -163,7 +180,10 @@ _pager_do_write_request (mach_port_t object, for (i = 0; i < npages; i++) { if (omitdata & (1 << i)) - continue; + { + notified[i] = 0; + continue; + } if (pm_entries[i] & PM_WRITEWAIT) wakeup = 1; @@ -179,14 +199,22 @@ _pager_do_write_request (mach_port_t object, 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); + { + 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); + notified[i] = 0; + } else - munmap ((caddr_t) (data + (vm_page_size * i)), - vm_page_size); + { + munmap ((void *) (data + (vm_page_size * i)), + vm_page_size); + notified[i] = (! kcopy && p->notify_on_evict); + if (! kcopy) + pm_entries[i] &= ~PM_INCORE; + } pm_entries[i] &= ~(PM_PAGINGOUT | PM_PAGEINWAIT | PM_WRITEWAIT); } @@ -198,10 +226,29 @@ _pager_do_write_request (mach_port_t object, if (wakeup) pthread_cond_broadcast (&p->wakeup); + notify: _pager_allow_termination (p); - pthread_mutex_unlock (&p->interlock); + for (i = 0; i < npages; i++) + { + assert (notified[i] == 0 || notified[i] == 1); + if (notified[i]) + { + short *pm_entry = &pm_entries[i]; + + /* Do notify user. */ + pager_notify_evict (p->upi, offset + (i * vm_page_size)); + + /* Clear any error that is left. Notification on eviction + is used only to change association of page, so any + error may no longer be valid. */ + pthread_mutex_lock (&p->interlock); + *pm_entry = SET_PM_ERROR (SET_PM_NEXTERROR (*pm_entry, 0), 0); + pthread_mutex_unlock (&p->interlock); + } + } + ports_port_deref (p); return 0; -- cgit v1.2.3