diff options
Diffstat (limited to 'libpager')
-rw-r--r-- | libpager/Makefile | 2 | ||||
-rw-r--r-- | libpager/data-return.c | 53 | ||||
-rw-r--r-- | libpager/pager-bulk.c | 37 | ||||
-rw-r--r-- | libpager/pager.h | 10 |
4 files changed, 94 insertions, 8 deletions
diff --git a/libpager/Makefile b/libpager/Makefile index 06fcb96b..169d5ab1 100644 --- a/libpager/Makefile +++ b/libpager/Makefile @@ -24,7 +24,7 @@ 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 demuxer.c chg-compl.c pager-attr.c clean.c \ dropweak.c get-upi.c pager-memcpy.c pager-return.c \ - offer-page.c pager-ro-port.c + offer-page.c pager-ro-port.c pager-bulk.c installhdrs = pager.h HURDLIBS= ports diff --git a/libpager/data-return.c b/libpager/data-return.c index a69a2c5c..1416ae41 100644 --- a/libpager/data-return.c +++ b/libpager/data-return.c @@ -158,14 +158,53 @@ _pager_do_write_request (struct pager *p, /* Let someone else in. */ pthread_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. */ + int i_page = 0; + while (i_page < npages) + { + if (omitdata & (1U << i_page)) + { + i_page++; + continue; + } + + /* Find maximal contiguous run [i_page, j_page) with no omitdata. */ + int j_page = i_page + 1; + while (j_page < npages && ! (omitdata & (1U << j_page))) + j_page++; + + vm_offset_t run_off = offset + (vm_page_size * i_page); + vm_address_t run_ptr = data + (vm_page_size * i_page); + vm_size_t run_len = vm_page_size * (j_page - i_page); + + vm_size_t wrote = 0; + + /* Attempt bulk write. */ + error_t berr = pager_write_pages (p->upi, run_off, run_ptr, + run_len, &wrote); + + /* How many pages did bulk actually complete? (only if not EOPNOTSUPP) */ + int pages_done = 0; + if (berr != EOPNOTSUPP) + { + if (wrote > run_len) + wrote = run_len; + wrote -= (wrote % vm_page_size); + pages_done = wrote / vm_page_size; + } + + /* Mark successful prefix (if any). */ + for (int k = 0; k < pages_done; k++) + pagerrs[i_page + k] = 0; + + /* Per-page the remaining suffix of the run, or the whole run if unsupported. */ + for (int k = i_page + pages_done; k < j_page; k++) + pagerrs[k] = pager_write_page (p->upi, + offset + (vm_page_size * k), + data + (vm_page_size * k)); + + i_page = j_page; + } - for (i = 0; i < npages; i++) - if (!(omitdata & (1U << i))) - pagerrs[i] = pager_write_page (p->upi, - offset + (vm_page_size * i), - data + (vm_page_size * i)); /* Acquire the right to meddle with the pagemap */ pthread_mutex_lock (&p->interlock); diff --git a/libpager/pager-bulk.c b/libpager/pager-bulk.c new file mode 100644 index 00000000..8dba01b5 --- /dev/null +++ b/libpager/pager-bulk.c @@ -0,0 +1,37 @@ +/* pager-bulk.c Default (dummy) implementation of bulk page write. + + Copyright (C) 2025 Free Software Foundation, Inc. + Written by Milos Nikic. + + 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 the GNU Hurd; if not, see <https://www.gnu.org/licenses/>. */ + +#include <libpager/pager.h> +#include "priv.h" + +/* Default dummy implementation of pager_write_pages. */ +__attribute__((weak)) error_t +pager_write_pages (struct user_pager_info *upi, + vm_offset_t offset, + vm_address_t data, vm_size_t length, vm_size_t *written) +{ + (void) upi; + (void) offset; + (void) data; + (void) length; + if (written) + *written = 0; + return EOPNOTSUPP; +} diff --git a/libpager/pager.h b/libpager/pager.h index 3b1c7251..8c43ad0e 100644 --- a/libpager/pager.h +++ b/libpager/pager.h @@ -203,6 +203,16 @@ pager_write_page (struct user_pager_info *pager, vm_offset_t page, vm_address_t buf); +/* The user may define this function. For pager PAGER, synchronously + write potentially multiple pages from DATA to offset. + Do not deallocate DATA, and do not keep any references to DATA. + The only permissible error returns are EIO, EDQUOT, EOPNOTSUPP, and ENOSPC. */ +error_t pager_write_pages(struct user_pager_info *upi, + vm_offset_t offset, + vm_address_t data, + vm_size_t length, + vm_size_t *written); + /* The user must define this function. A page should be made writable. */ error_t pager_unlock_page (struct user_pager_info *pager, |