summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2001-10-01 01:04:57 +0000
committerRoland McGrath <roland@gnu.org>2001-10-01 01:04:57 +0000
commitaf3199bd62a9f635e081af23a834bc47fce83bc6 (patch)
treecf9310d725f132436c2ed3777c86c1497cffd67e
parentdd033a2bbced5e561c0e692bf3da2a43bad435ae (diff)
2001-09-30 Roland McGrath <roland@frob.com>
* memobj.c: New file. * Makefile (SRCS): Add it. * store.h (store_memobj_class, store_memobj_create): Declare them.
-rw-r--r--libstore/Makefile2
-rw-r--r--libstore/memobj.c188
-rw-r--r--libstore/store.h8
3 files changed, 197 insertions, 1 deletions
diff --git a/libstore/Makefile b/libstore/Makefile
index 4825f76e..7795b97a 100644
--- a/libstore/Makefile
+++ b/libstore/Makefile
@@ -26,7 +26,7 @@ libname = libstore
SRCS = create.c derive.c make.c rdwr.c set.c device.c file.c stripe.c \
enc.c encode.c decode.c clone.c argp.c std.c kids.c zero.c flags.c \
open.c remap.c xinl.c task.c typed.c copy.c gunzip.c map.c mvol.c \
- bunzip2.c part.c nbd.c
+ bunzip2.c part.c nbd.c memobj.c
LCLHDRS=store.h
installhdrs=store.h
diff --git a/libstore/memobj.c b/libstore/memobj.c
new file mode 100644
index 00000000..6205b596
--- /dev/null
+++ b/libstore/memobj.c
@@ -0,0 +1,188 @@
+/* Store backend using a Mach memory object
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <hurd.h>
+#include <hurd/store.h>
+#include <hurd/sigpreempt.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <assert.h>
+
+
+/* Return a new store in STORE referring to the memory object MEMOBJ.
+ Consumes the send right MEMOBJ. */
+error_t
+store_memobj_create (memory_object_t memobj, int flags, size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ return _store_create (&store_memobj_class,
+ memobj, flags, block_size, runs, num_runs, 0, store);
+}
+
+
+/* This one is pretty easy. */
+static error_t
+memobj_map (const struct store *store, vm_prot_t prot, mach_port_t *memobj)
+{
+ *memobj = store->port;
+ return mach_port_mod_refs (mach_task_self (), *memobj,
+ MACH_PORT_RIGHT_SEND, +1);
+}
+
+
+static error_t /* swiped from libpager's pager_memcpy */
+memobj_memcpy (memory_object_t memobj,
+ vm_offset_t offset, void *other, size_t *size,
+ vm_prot_t prot)
+{
+ vm_address_t window = 0;
+ vm_size_t windowsize = 8 * vm_page_size;
+ size_t to_copy = *size;
+ error_t err;
+
+ error_t copy (struct hurd_signal_preemptor *preemptor)
+ {
+ while (to_copy > 0)
+ {
+ size_t pageoff = offset & (vm_page_size - 1);
+
+ if (window)
+ /* Deallocate the old window. */
+ munmap ((caddr_t) window, windowsize);
+
+ /* Map in and copy a standard-sized window, unless that is
+ more than the total left to be copied. */
+
+ if (windowsize > pageoff + to_copy)
+ windowsize = pageoff + to_copy;
+
+ window = 0;
+ err = vm_map (mach_task_self (), &window, windowsize, 0, 1,
+ memobj, offset - pageoff, 0,
+ prot, prot, VM_INHERIT_NONE);
+ if (err)
+ return 0;
+
+ /* Realign the fault preemptor for the new mapping window. */
+ preemptor->first = window;
+ preemptor->last = window + windowsize;
+
+ if (prot == VM_PROT_READ)
+ memcpy (other, (const void *) window + pageoff,
+ windowsize - pageoff);
+ else
+ memcpy ((void *) window + pageoff, other, windowsize - pageoff);
+
+ offset += windowsize - pageoff;
+ other += windowsize - pageoff;
+ to_copy -= windowsize - pageoff;
+ }
+ return 0;
+ }
+
+ jmp_buf buf;
+ void fault (int signo, long int sigcode, struct sigcontext *scp)
+ {
+ assert (scp->sc_error == EKERN_MEMORY_ERROR);
+ err = EIO;
+ to_copy -= sigcode - window;
+ longjmp (buf, 1);
+ }
+
+ if (to_copy == 0)
+ /* Short-circuit return if nothing to do.
+ ERR would not be initialized by the copy loop in this case. */
+ return 0;
+
+ if (setjmp (buf) == 0)
+ hurd_catch_signal (sigmask (SIGSEGV) | sigmask (SIGBUS),
+ window, window + windowsize,
+ &copy, (sighandler_t) &fault);
+
+ if (window)
+ munmap ((caddr_t) window, windowsize);
+
+ *size -= to_copy;
+
+ return err;
+}
+
+static error_t
+memobj_read (struct store *store,
+ store_offset_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
+{
+ addr <<= store->log2_block_size;
+ if (((size_t) addr & (vm_page_size - 1)) == 0)
+ {
+ *len = amount;
+ return vm_map (mach_task_self (), (vm_address_t *) buf, amount,
+ 0, 1, store->port, addr << store->log2_block_size, 0,
+ VM_PROT_READ, VM_PROT_ALL, VM_INHERIT_NONE);
+ }
+ else
+ {
+ error_t err;
+ int alloced = 0;
+ if (*len < amount)
+ {
+ *buf = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*buf == MAP_FAILED)
+ return errno;
+ alloced = 1;
+ }
+ *len = amount;
+ err = memobj_memcpy (store->port, addr, *buf, len, VM_PROT_READ);
+ if (err && alloced)
+ munmap (*buf, amount);
+ else if (alloced && round_page (*len) < round_page (amount))
+ munmap (*buf + round_page (*len),
+ round_page (amount) - round_page (*len));
+ return err;
+ }
+}
+
+static error_t
+memobj_write (struct store *store,
+ store_offset_t addr, size_t index,
+ const void *buf, size_t len, size_t *amount)
+{
+ *amount = len;
+ return memobj_memcpy (store->port, addr << store->log2_block_size,
+ (void *) buf, amount, VM_PROT_WRITE);
+}
+
+static error_t
+memobj_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ return store_std_leaf_decode (enc, store_memobj_create, store);
+}
+
+struct store_class store_memobj_class =
+{
+ STORAGE_MEMORY, "memobj",
+ map: memobj_map,
+ read: memobj_read,
+ write: memobj_write,
+ allocate_encoding: store_std_leaf_allocate_encoding,
+ encode: store_std_leaf_encode,
+ decode: memobj_decode,
+};
diff --git a/libstore/store.h b/libstore/store.h
index d7f687d3..a8ff49fe 100644
--- a/libstore/store.h
+++ b/libstore/store.h
@@ -382,6 +382,13 @@ error_t _store_task_create (task_t task, int flags, size_t block_size,
corresponding store in STORE. */
error_t store_task_open (const char *name, int flags, struct store **store);
+/* Return a new store in STORE referring to the memory object MEMOBJ.
+ Consumes the send right MEMOBJ. */
+error_t store_memobj_create (memory_object_t memobj, int flags,
+ size_t block_size,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store);
+
/* Open the network block device NAME (parsed as "HOSTNAME:PORT[/BLOCKSIZE]"),
and return the corresponding store in STORE. This opens a socket and
initial connection handshake, which determine the size of the device,
@@ -509,6 +516,7 @@ extern const struct store_class store_part_class;
extern const struct store_class store_file_class;
extern const struct store_class store_task_class;
extern const struct store_class store_nbd_class;
+extern const struct store_class store_memobj_class;
extern const struct store_class store_zero_class;
extern const struct store_class store_ileave_class;
extern const struct store_class store_concat_class;