aboutsummaryrefslogtreecommitdiff
path: root/libstore/stripe.c
diff options
context:
space:
mode:
Diffstat (limited to 'libstore/stripe.c')
-rw-r--r--libstore/stripe.c282
1 files changed, 282 insertions, 0 deletions
diff --git a/libstore/stripe.c b/libstore/stripe.c
new file mode 100644
index 00000000..59fb504e
--- /dev/null
+++ b/libstore/stripe.c
@@ -0,0 +1,282 @@
+/* Striped store backend
+
+ Copyright (C) 1996,97,99 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ 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 "store.h"
+
+extern long lcm (long p, long q);
+
+/* Return ADDR adjust for any block size difference between STORE and
+ STRIPE. We assume that STORE's block size is no less than STRIPE's. */
+static inline off_t
+addr_adj (off_t addr, struct store *store, struct store *stripe)
+{
+ unsigned common_bs = store->log2_block_size;
+ unsigned stripe_bs = stripe->log2_block_size;
+ if (common_bs == stripe_bs)
+ return addr;
+ else
+ return addr << (common_bs - stripe_bs);
+}
+
+static error_t
+stripe_read (struct store *store,
+ off_t addr, size_t index, size_t amount,
+ void **buf, size_t *len)
+{
+ struct store *stripe = store->children[index];
+ return store_read (stripe, addr_adj (addr, store, stripe), amount, buf, len);
+}
+
+static error_t
+stripe_write (struct store *store,
+ off_t addr, size_t index, void *buf, size_t len,
+ size_t *amount)
+{
+ struct store *stripe = store->children[index];
+ return
+ store_write (stripe, addr_adj (addr, store, stripe), buf, len, amount);
+}
+
+error_t
+stripe_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);
+}
+
+error_t
+ileave_allocate_encoding (const struct store *store, struct store_enc *enc)
+{
+ enc->num_ints += 4;
+ return store_allocate_child_encodings (store, enc);
+}
+
+error_t
+ileave_encode (const struct store *store, struct store_enc *enc)
+{
+ enc->ints[enc->cur_int++] = store->class->id;
+ enc->ints[enc->cur_int++] = store->flags;
+ enc->ints[enc->cur_int++] = store->wrap_dst; /* interleave factor */
+ enc->ints[enc->cur_int++] = store->num_children;
+ return store_encode_children (store, enc);
+}
+
+error_t
+ileave_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ if (enc->cur_int + 4 > enc->num_ints)
+ return EINVAL;
+ else
+ {
+ int type __attribute__((unused)) = enc->ints[enc->cur_int++];
+ int flags = enc->ints[enc->cur_int++];
+ int interleave = enc->ints[enc->cur_int++];
+ int nkids = enc->ints[enc->cur_int++];
+ struct store *kids[nkids];
+ error_t err = store_decode_children (enc, nkids, classes, kids);
+ if (! err)
+ err = store_ileave_create (kids, nkids, interleave, flags, store);
+ return err;
+ }
+}
+
+struct store_class
+store_ileave_class =
+{
+ STORAGE_INTERLEAVE, "interleave", stripe_read, stripe_write,
+ ileave_allocate_encoding, ileave_encode, ileave_decode,
+ store_set_child_flags, store_clear_child_flags, 0, 0, stripe_remap
+};
+
+error_t
+concat_allocate_encoding (const struct store *store, struct store_enc *enc)
+{
+ enc->num_ints += 3;
+ return store_allocate_child_encodings (store, enc);
+}
+
+error_t
+concat_encode (const struct store *store, struct store_enc *enc)
+{
+ enc->ints[enc->cur_int++] = store->class->id;
+ enc->ints[enc->cur_int++] = store->flags;
+ enc->ints[enc->cur_int++] = store->num_children;
+ return store_encode_children (store, enc);
+}
+
+error_t
+concat_decode (struct store_enc *enc, const struct store_class *const *classes,
+ struct store **store)
+{
+ if (enc->cur_int + 3 > enc->num_ints)
+ return EINVAL;
+ else
+ {
+ int type __attribute__((unused)) = enc->ints[enc->cur_int++];
+ int flags = enc->ints[enc->cur_int++];
+ int nkids = enc->ints[enc->cur_int++];
+ struct store *kids[nkids];
+ error_t err = store_decode_children (enc, nkids, classes, kids);
+ if (! err)
+ err = store_concat_create (kids, nkids, flags, store);
+ return err;
+ }
+}
+
+struct store_class
+store_concat_class =
+{
+ STORAGE_CONCAT, "concat", stripe_read, stripe_write,
+ concat_allocate_encoding, concat_encode, concat_decode,
+ store_set_child_flags, store_clear_child_flags, 0, 0, stripe_remap
+};
+
+/* Return a new store in STORE that interleaves all the stores in STRIPES
+ (NUM_STRIPES of them) every INTERLEAVE bytes; INTERLEAVE must be an
+ integer multiple of each stripe's block size. The stores in STRIPES are
+ consumed -- that is, will be freed when this store is (however, the
+ *array* STRIPES is copied, and so should be freed by the caller). */
+error_t
+store_ileave_create (struct store *const *stripes, size_t num_stripes,
+ off_t interleave, int flags, struct store **store)
+{
+ size_t i;
+ error_t err;
+ off_t block_size = 1, min_end = 0;
+ struct store_run runs[num_stripes];
+ int common_flags = STORE_BACKEND_FLAGS;
+
+ /* Find a common block size. */
+ for (i = 0; i < num_stripes; i++)
+ block_size = lcm (block_size, stripes[i]->block_size);
+
+ if (interleave < block_size || (interleave % block_size) != 0)
+ return EINVAL;
+
+ interleave /= block_size;
+
+ for (i = 0; i < num_stripes; i++)
+ {
+ /* The stripe's end adjusted to the common block size. */
+ off_t end = stripes[i]->end;
+
+ runs[i].start = 0;
+ runs[i].length = interleave;
+
+ if (stripes[i]->block_size != block_size)
+ end /= (block_size / stripes[i]->block_size);
+
+ if (min_end < 0)
+ min_end = end;
+ else if (min_end > end)
+ /* Only use as much space as the smallest stripe has. */
+ min_end = end;
+
+ common_flags &= stripes[i]->flags;
+ }
+
+ err = _store_create (&store_ileave_class, MACH_PORT_NULL,
+ common_flags | flags, block_size,
+ runs, num_stripes, min_end, store);
+ if (! err)
+ {
+ (*store)->wrap_dst = interleave;
+
+ err = store_set_children (*store, stripes, num_stripes);
+ if (err)
+ store_free (*store);
+ }
+
+ return err;
+}
+
+/* Return a new store in STORE that concatenates all the stores in STORES
+ (NUM_STORES of them). The stores in STRIPES are consumed -- that is, will
+ be freed when this store is (however, the *array* STRIPES is copied, and
+ so should be freed by the caller). */
+error_t
+store_concat_create (struct store * const *stores, size_t num_stores,
+ int flags, struct store **store)
+{
+ size_t i;
+ error_t err;
+ off_t block_size = 1;
+ int common_flags = STORE_BACKEND_FLAGS;
+ struct store_run runs[num_stores];
+
+ /* Find a common block size. */
+ for (i = 0; i < num_stores; i++)
+ block_size = lcm (block_size, stores[i]->block_size);
+
+ for (i = 0; i < num_stores; i++)
+ {
+ runs[i].start = 0;
+ runs[i].length = stores[i]->end;
+ common_flags &= stores[i]->flags;
+ }
+
+ err = _store_create (&store_concat_class, MACH_PORT_NULL,
+ flags | common_flags, block_size,
+ runs, num_stores * 2, 0, store);
+ if (! err)
+ {
+ err = store_set_children (*store, stores, num_stores);
+ if (! err)
+ {
+ err = store_children_name (*store, &(*store)->name);
+ if (err == EINVAL)
+ err = 0; /* Can't find a name; deal. */
+ }
+ if (err)
+ store_free (*store);
+ }
+
+ return err;
+}
+
+/* Return a new store that concatenates the stores created by opening all the
+ individual stores described in NAME; for the syntax of NAME, see
+ store_open_children. */
+error_t
+store_concat_open (const char *name, int flags,
+ const struct store_class *const *classes,
+ struct store **store)
+{
+ struct store **stores;
+ size_t num_stores;
+ error_t err =
+ store_open_children (name, flags, classes, &stores, &num_stores);
+ if (! err)
+ {
+ err = store_concat_create (stores, num_stores, flags, store);
+ if (err)
+ {
+ size_t k;
+ for (k = 0; k < (*store)->num_children; k++)
+ store_free ((*store)->children[k]);
+ }
+ }
+ return err;
+}