diff options
-rw-r--r-- | mach-defpager/Makefile | 13 | ||||
-rw-r--r-- | mach-defpager/file_io.h | 69 | ||||
-rw-r--r-- | mach-defpager/setup.c | 294 |
3 files changed, 368 insertions, 8 deletions
diff --git a/mach-defpager/Makefile b/mach-defpager/Makefile index ef59ed1f..96068fc2 100644 --- a/mach-defpager/Makefile +++ b/mach-defpager/Makefile @@ -22,15 +22,12 @@ dir := mach-defpager makemode:= server target := mach-defpager -SRCS := default_pager.c def_pager_setup.c \ - kalloc.c wiring.c main.c \ - file_io.c strfcns.c \ - ext2_file_io.c ffs_file_io.c ffs_compat.c \ - minix_file_io.c minix_ffs_compat.c - -OBJS = $(SRCS:.c=.o) \ - $(addsuffix Server.o,memory_object default_pager memory_object_default \ +SRCS := default_pager.c kalloc.c wiring.c main.c setup.c +OBJS := $(SRCS:.c=.o) \ + $(addsuffix Server.o,\ + memory_object default_pager memory_object_default \ exc bootstrap) +# None of those pay attention to SERVERPREFIX. HURDLIBS:= threads LDFLAGS += -static diff --git a/mach-defpager/file_io.h b/mach-defpager/file_io.h new file mode 100644 index 00000000..d0b03f33 --- /dev/null +++ b/mach-defpager/file_io.h @@ -0,0 +1,69 @@ +/* Backing store access callbacks for Hurd version of Mach default pager. + Copyright (C) 2000 Free Software Foundation, Inc. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _file_io_h +#define _file_io_h 1 + +/* The original Mach default pager code used in serverboot can read + filesystem meta-data to find the blocks used by paging files. + We replace those interfaces with simpler code that only supports + subsets of devices represented by a list of runs a la libstore. */ + +#include <sys/types.h> + +#include <device/device_types.h> +#include <device/device.h> + +/* A run of device records, expressed in the device's record size. */ +struct storage_run +{ + recnum_t start, length; +}; + +struct file_direct +{ + mach_port_t device; + + int bshift; /* size of device records (disk blocks) */ + size_t fd_bsize; /* log2 of that */ + recnum_t fd_size; /* number of blocks total */ + + /* The paging area consists of the concatentation of NRUNS contiguous + regions of the device, as described by RUNS. */ + size_t nruns; + struct storage_run runs[0]; +}; + +/* These are in fact only called to read or write a single page, from + default_pager.c::default_read/default_write. The SIZE argument is + always vm_page_size and OFFSET is always page-aligned. */ + +int page_read_file_direct (struct file_direct *fdp, + vm_offset_t offset, + vm_size_t size, + vm_offset_t *addr, /* out */ + mach_msg_type_number_t *size_read); /* out */ +int page_write_file_direct(struct file_direct *fdp, + vm_offset_t offset, + vm_offset_t addr, + vm_size_t size, + vm_offset_t *size_written); /* out */ + + +#endif /* file_io.h */ diff --git a/mach-defpager/setup.c b/mach-defpager/setup.c new file mode 100644 index 00000000..134036ae --- /dev/null +++ b/mach-defpager/setup.c @@ -0,0 +1,294 @@ +/* Backing store access callbacks for Hurd version of Mach default pager. + Copyright (C) 2001 Free Software Foundation, Inc. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <errno.h> +#include <stddef.h> +#include <assert.h> +#include <mach.h> + +#include "file_io.h" +#include "default_pager_S.h" + +/* This should be in some system header... XXX */ +static inline int page_aligned (vm_offset_t num) +{ + return trunc_page (num) == num; +} + +/* From serverboot/kalloc.c. */ +extern void *kalloc (vm_size_t); + +kern_return_t +default_pager_paging_storage (mach_port_t pager, + mach_port_t device, + recnum_t *runs, mach_msg_type_number_t nrun, + default_pager_filename_t name, + boolean_t add) +{ + struct file_direct *fdp; + int sizes[DEV_GET_SIZE_COUNT]; + natural_t count; + mach_msg_type_number_t i; + error_t err; + recnum_t devsize; + + if (! add) + return remove_paging_file (name); /* XXX ? */ + + if (nrun < 2 || nrun % 2 != 0) + return EINVAL; + + count = DEV_GET_SIZE_COUNT; + err = device_get_status (device, DEV_GET_SIZE, sizes, &count); + if (err) + return err; + if (count < DEV_GET_SIZE_COUNT || sizes[DEV_GET_SIZE_RECORD_SIZE] <= 0) + return EINVAL; + devsize = sizes[DEV_GET_SIZE_DEVICE_SIZE] / sizes[DEV_GET_SIZE_RECORD_SIZE]; + + if (vm_page_size % sizes[DEV_GET_SIZE_RECORD_SIZE] != 0) + /* We can't write disk blocks larger than pages. */ + return EINVAL; + + fdp = kalloc (offsetof (struct file_direct, runs[nrun])); + if (fdp == 0) + return ENOMEM; + + fdp->device = device; + fdp->bshift = ffs (sizes[DEV_GET_SIZE_RECORD_SIZE]) - 1; + fdp->fd_bsize = sizes[DEV_GET_SIZE_RECORD_SIZE]; + fdp->nruns = nrun / 2; + fdp->fd_size = 0; + for (i = 0; i < nrun; i += 2) + { + fdp->runs[i].start = runs[i]; + fdp->runs[i].length = runs[i + 1]; + if (fdp->runs[i].start + fdp->runs[i].length > devsize) + { + kfree (fdp); + return EINVAL; + } + fdp->fd_size += fdp->runs[i].length; + } + + /* Now really do it. */ + create_paging_partition (name, fdp, 0, -3); + return 0; +} + + +/* Called to read a page from backing store. */ +int +page_read_file_direct (struct file_direct *fdp, + vm_offset_t offset, + vm_size_t size, + vm_offset_t *addr, /* out */ + mach_msg_type_number_t *size_read) /* out */ +{ + struct storage_run *r; + error_t err; + char *readloc; + char *page; + mach_msg_type_number_t nread; + + assert (page_aligned (offset)); + assert (size == vm_page_size); + + offset >>= fdp->bshift; + + assert (offset + (size >> fdp->bshift) <= fdp->fd_size); + + /* Find the run containing the beginning of the page. */ + for (r = fdp->runs; r->length > offset; ++r) + offset -= r->length; + + if (offset + (size >> fdp->bshift) <= r->length) + /* The first run contains the whole page. */ + return device_read (fdp->device, 0, + r->start + offset, size >> fdp->bshift, + (char **) addr, size_read); + + /* Read the first part of the run. */ + err = device_read (fdp->device, 0, r->start + offset, r->length - offset, + (char **) addr, &nread); + if (err) + return err; + + size -= nread; + readloc = (char *) *addr; + do + { + readloc += nread; + offset += nread >> fdp->bshift; + if (r->length > offset) + offset -= r++->length; + + /* We always get another out-of-line page, so we have to copy + out of that page and deallocate it. */ + err = device_read (fdp->device, 0, r->start + offset, r->length - offset, + &page, &nread); + if (err) + { + vm_deallocate (mach_task_self (), + (vm_address_t) *addr, vm_page_size); + return err; + } + memcpy (readloc, page, nread); + vm_deallocate (mach_task_self (), (vm_address_t) page, vm_page_size); + size -= nread; + } while (size > 0); + + *size_read = vm_page_size; + return 0; +} + +/* Called to write a page to backing store. */ +int +page_write_file_direct(struct file_direct *fdp, + vm_offset_t offset, + vm_offset_t addr, + vm_size_t size, + vm_offset_t *size_written) /* out */ +{ + struct storage_run *r; + error_t err; + int wrote; + + assert (page_aligned (offset)); + assert (size == vm_page_size); + + offset >>= fdp->bshift; + + assert (offset + (size >> fdp->bshift) <= fdp->fd_size); + + /* Find the run containing the beginning of the page. */ + for (r = fdp->runs; r->length > offset; ++r) + offset -= r->length; + + if (offset + (size >> fdp->bshift) <= r->length) + /* The first run contains the whole page. */ + return device_write (fdp->device, 0, + r->start + offset, (char *) addr, size, &wrote); + + /* Write the first part of the run. */ + err = device_write (fdp->device, 0, + r->start + offset, (char *) addr, + (r->length - offset) << fdp->bshift, + &wrote); + if (err) + return err; + + size -= wrote; + do + { + mach_msg_type_number_t segsize; + + addr += wrote; + offset += wrote >> fdp->bshift; + if (r->length > offset) + offset -= r++->length; + + segsize = (r->length - offset) >> fdp->bshift; + if (segsize > size) + segsize = size; + err = device_write (fdp->device, 0, + r->start + offset, (char *) addr, segsize, &wrote); + if (err) + { + vm_deallocate (mach_task_self (), + (vm_address_t) addr, vm_page_size); + return err; + } + + size -= wrote; + } while (size > 0); + + *size_written = vm_page_size; + return 0; +} + + +/* Compatibility entry points used by default_pager_paging_file RPC. */ + +kern_return_t +add_paging_file(master_device_port, file_name, linux_signature) + mach_port_t master_device_port; + char *file_name; + int linux_signature; +{ + error_t err; + mach_port_t dev; + int sizes[DEV_GET_SIZE_COUNT]; + natural_t count; + char *devname = file_name; + + assert (linux_signature == 0); + + if (!strncmp (file_name, "/dev/", 5)) + devname += 5; + + err = device_open (master_device_port, D_READ|D_WRITE, devname, &dev); + if (err) + return err; + + count = DEV_GET_SIZE_COUNT; + err = device_get_status (dev, DEV_GET_SIZE, sizes, &count); + if (!err && count < DEV_GET_SIZE_COUNT) + err = EGRATUITOUS; + if (err) + mach_port_deallocate (mach_task_self (), dev); + else + { + struct file_direct *fdp; + fdp = kalloc (offsetof (struct file_direct, runs[1])); + if (fdp == 0) + return ENOMEM; + + fdp->device = dev; + fdp->fd_bsize = sizes[DEV_GET_SIZE_RECORD_SIZE]; + fdp->bshift = ffs (sizes[DEV_GET_SIZE_RECORD_SIZE]) - 1; + fdp->fd_size = sizes[DEV_GET_SIZE_DEVICE_SIZE] >> fdp->bshift; + fdp->nruns = 1; + fdp->runs[0].start = 0; + fdp->runs[0].length = fdp->fd_size; + + /* Now really do it. */ + create_paging_partition (file_name, fdp, 0, 0); + } + + return err; +} + +/* + * Destroy a paging_partition given a file name + */ +kern_return_t +remove_paging_file (char *file_name) +{ + struct file_direct *fdp = 0; + kern_return_t kr; + + kr = destroy_paging_partition(file_name, &fdp); + if (kr == KERN_SUCCESS && fdp != 0) + { + mach_port_deallocate (mach_task_self (), fdp->device); + kfree (fdp, (char *) &fdp->runs[fdp->nruns] - (char *) fdp); + } + return kr; +} |