summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libstore/mvol.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/libstore/mvol.c b/libstore/mvol.c
new file mode 100644
index 00000000..b0753dac
--- /dev/null
+++ b/libstore/mvol.c
@@ -0,0 +1,151 @@
+/* Multiple-volume store backend
+
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+ 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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "store.h"
+
+struct mvol_state
+{
+ /* The current `volume'. */
+ ssize_t cur_vol;
+
+ /* A function to change volumes, making NEW_VOL readable on the store
+ instead of OLD_VOL. OLD_VOL is initially -1, */
+ error_t (*swap_vols) (struct store *store, size_t new_vol, ssize_t old_vol);
+};
+
+static error_t
+ensure_vol (struct store *store, size_t vol)
+{
+ error_t err = 0;
+ struct mvol_state *mv = store->hook;
+ if (vol != mv->cur_vol)
+ {
+ err = (*mv->swap_vols) (store, vol, mv->cur_vol);
+ if (! err)
+ mv->cur_vol = vol;
+ }
+ return err;
+}
+
+static error_t
+mvol_read (struct store *store,
+ off_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
+{
+ error_t err = ensure_vol (store, index);
+ if (! err)
+ err = store_read (store->children[0], addr, amount, buf, len);
+ return err;
+}
+
+static error_t
+mvol_write (struct store *store,
+ off_t addr, size_t index, void *buf, size_t len,
+ size_t *amount)
+{
+ error_t err = ensure_vol (store, index);
+ if (! err)
+ err = store_write (store->children[0], addr, buf, len, amount);
+ return err;
+}
+
+error_t
+mvol_remap (struct store *source,
+ const struct store_run *runs, size_t num_runs,
+ struct store **store)
+{
+ return store_remap_create (source, runs, num_runs, 0, store);
+}
+
+struct store_class
+store_mvol_class =
+{
+ -1, "mvol", mvol_read, mvol_write,
+ 0, 0, 0,
+ store_set_child_flags, store_clear_child_flags, 0, 0, mvol_remap
+};
+
+/* Return a new store in STORE that multiplexes multiple physical volumes
+ from PHYS as one larger virtual volume. SWAP_VOLS is a function that will
+ be called whenever the volume currently active isn't correct. PHYS is
+ consumed. */
+error_t
+store_mvol_create (struct store *phys,
+ error_t (*swap_vols) (struct store *store, size_t new_vol,
+ ssize_t old_vol),
+ int flags,
+ struct store **store)
+{
+ error_t err;
+ struct store_run run;
+
+ run.start = 0;
+ run.length = phys->end;
+
+ err = _store_create (&store_mvol_class, MACH_PORT_NULL,
+ flags | phys->flags, phys->block_size,
+ &run, 1, 0, store);
+ if (! err)
+ {
+ struct mvol_state *mv = malloc (sizeof (struct mvol_state));
+ if (mv)
+ {
+ mv->swap_vols = swap_vols;
+ mv->cur_vol = -1;
+ (*store)->hook = mv;
+ }
+ else
+ err = ENOMEM;
+
+ if (! err)
+ err = store_set_children (*store, &phys, 1);
+
+ if (! err)
+ {
+ if (phys->name)
+ {
+ size_t nlen =
+ strlen (phys->class->name) + 1 + strlen (phys->name) + 1;
+ char *name = malloc (nlen);
+
+ if (name)
+ {
+ snprintf (name, nlen, "%s:%s", phys->class->name, phys->name);
+ (*store)->name = name;
+ }
+ else
+ err = ENOMEM;
+ }
+ }
+
+ if (err)
+ {
+ if (mv)
+ free (mv);
+ store_free (*store);
+ }
+ }
+
+ return err;
+}