1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-03-13 00:58:47 +03:00
lvm2/driver/device-mapper/dm-stripe.c
Steven Whitehouse a9a572e8a1 o Initial merge attempt
There are still a few odd things going on, so more debugging remains to be
done.
2001-12-05 11:28:41 +00:00

186 lines
3.8 KiB
C

/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/device-mapper.h>
#include "dm.h"
struct stripe {
struct dm_dev *dev;
offset_t physical_start;
};
struct stripe_c {
offset_t logical_start;
uint32_t stripes;
/* The size of this target / num. stripes */
uint32_t stripe_width;
/* eg, we stripe in 64k chunks */
uint32_t chunk_shift;
offset_t chunk_mask;
struct stripe stripe[0];
};
static inline struct stripe_c *alloc_context(int stripes)
{
size_t len = sizeof(struct stripe_c) +
(sizeof(struct stripe) * stripes);
return kmalloc(len, GFP_KERNEL);
}
/*
* parses a single <dev> <sector> pair.
*/
static int get_stripe(struct dm_table *t, struct stripe_c *sc,
int stripe, char *args)
{
int n, r;
char path[256]; /* FIXME: buffer overrun risk */
unsigned long start;
if (sscanf(args, "%s %lu %n", path, &start, &n) != 2)
return -EINVAL;
if ((r = dm_table_get_device(t, path, start, sc->stripe_width,
&sc->stripe[stripe].dev)))
return -ENXIO;
sc->stripe[stripe].physical_start = start;
return n;
}
/*
* construct a striped mapping.
* <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+
*/
static int stripe_ctr(struct dm_table *t, offset_t b, offset_t l,
char *args, void **context)
{
struct stripe_c *sc;
uint32_t stripes;
uint32_t chunk_size;
int n, i;
*context = "couldn't parse <stripes> <chunk size>";
if (sscanf(args, "%u %u %n", &stripes, &chunk_size, &n) != 2) {
return -EINVAL;
}
*context = "target length is not divisable by the number of stripes";
if (l % stripes) {
return -EINVAL;
}
*context = "couldn't allocate memory for striped context";
if (!(sc = alloc_context(stripes))) {
return -ENOMEM;
}
sc->logical_start = b;
sc->stripes = stripes;
sc->stripe_width = l / stripes;
/*
* chunk_size is a power of two. We only
* that power and the mask.
*/
*context = "invalid chunk size";
if (!chunk_size) {
return -EINVAL;
}
sc->chunk_mask = chunk_size - 1;
for (sc->chunk_shift = 0; chunk_size; sc->chunk_shift++)
chunk_size >>= 1;
sc->chunk_shift--;
/*
* Get the stripe destinations.
*/
for (i = 0; i < stripes; i++) {
args += n;
n = get_stripe(t, sc, i, args);
*context = "couldn't parse stripe destination";
if (n < 0) {
kfree(sc);
return n;
}
}
*context = sc;
return 0;
}
static void stripe_dtr(struct dm_table *t, void *c)
{
unsigned int i;
struct stripe_c *sc = (struct stripe_c *) c;
for (i = 0; i < sc->stripes; i++)
dm_table_put_device(t, sc->stripe[i].dev);
kfree(sc);
}
static int stripe_map(struct buffer_head *bh, int rw, void *context)
{
struct stripe_c *sc = (struct stripe_c *) context;
offset_t offset = bh->b_rsector - sc->logical_start;
uint32_t chunk = (uint32_t) (offset >> sc->chunk_shift);
uint32_t stripe = chunk % sc->stripes; /* 32bit modulus */
chunk = chunk / sc->stripes;
bh->b_rdev = sc->stripe[stripe].dev->dev;
bh->b_rsector = sc->stripe[stripe].physical_start +
(chunk << sc->chunk_shift) +
(offset & sc->chunk_mask);
return 1;
}
static struct target_type stripe_target = {
name: "striped",
module: THIS_MODULE,
ctr: stripe_ctr,
dtr: stripe_dtr,
map: stripe_map,
};
static int __init stripe_init(void)
{
int r;
if ((r = dm_register_target(&stripe_target)) < 0)
WARN("linear target register failed");
return r;
}
static void __exit stripe_exit(void)
{
if (dm_unregister_target(&stripe_target))
WARN("striped target unregister failed");
}
module_init(stripe_init);
module_exit(stripe_exit);
MODULE_AUTHOR("Joe Thornber <thornber@sistina.com>");
MODULE_DESCRIPTION("Device Mapper: Striped mapping");
MODULE_LICENSE("GPL");