summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mach-defpager/Makefile13
-rw-r--r--mach-defpager/file_io.h69
-rw-r--r--mach-defpager/setup.c294
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;
+}