mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
o split struct mapped_device into mapped_device and dm_table
o seperated loading of a table from binding a table to the device These should allow multiple tables to be managed by dm-fs
This commit is contained in:
parent
4183d3fe6c
commit
0f29dc2f2d
@ -35,11 +35,11 @@
|
||||
/* FIXME: Use value from local range for now, for co-existence with LVM 1 */
|
||||
#define DM_BLK_MAJOR 124
|
||||
|
||||
struct mapped_device;
|
||||
struct dm_table;
|
||||
typedef unsigned int offset_t;
|
||||
|
||||
/* constructor, destructor and map fn types */
|
||||
typedef int (*dm_ctr_fn)(offset_t b, offset_t e, struct mapped_device *md,
|
||||
typedef int (*dm_ctr_fn)(offset_t b, offset_t e, struct dm_table *t,
|
||||
const char *cb, const char *ce, void **result);
|
||||
typedef void (*dm_dtr_fn)(void *c);
|
||||
typedef int (*dm_map_fn)(struct buffer_head *bh, void *context);
|
||||
@ -47,9 +47,12 @@ typedef int (*dm_map_fn)(struct buffer_head *bh, void *context);
|
||||
int register_map_target(const char *name, dm_ctr_fn ctr, dm_dtr_fn dtr,
|
||||
dm_map_fn map);
|
||||
|
||||
/* contructors should call this to make sure any destination devices
|
||||
are handled correctly (ie. opened/closed) */
|
||||
int dm_add_device(struct mapped_device *md, kdev_t dev);
|
||||
|
||||
/* contructors should call this to make sure any
|
||||
* destination devices are handled correctly
|
||||
* (ie. opened/closed).
|
||||
*/
|
||||
int dm_table_add_device(struct dm_table *t, kdev_t dev);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -49,21 +49,25 @@ static struct proc_dir_entry *_control;
|
||||
|
||||
static devfs_handle_t _dev_dir;
|
||||
|
||||
static int process_control(const char *b, const char *e, int minor,
|
||||
struct dm_table **map);
|
||||
static int process_table(const char *b, const char *e, int minor,
|
||||
struct dm_table **map);
|
||||
static int line_splitter(struct file *file, const char *buffer,
|
||||
unsigned long count, void *data);
|
||||
static int process_control(const char *b, const char *e, int minor);
|
||||
static int process_table(const char *b, const char *e, int minor);
|
||||
static int get_word(const char *b, const char *e,
|
||||
const char **wb, const char **we);
|
||||
static int tok_cmp(const char *str, const char *b, const char *e);
|
||||
static void tok_cpy(char *dest, size_t max,
|
||||
const char *b, const char *e);
|
||||
|
||||
typedef int (*process_fn)(const char *b, const char *e, int minor);
|
||||
typedef int (*process_fn)(const char *b, const char *e, int minor,
|
||||
struct dm_table **map);
|
||||
|
||||
struct pf_data {
|
||||
process_fn fn;
|
||||
int minor;
|
||||
struct dm_table *map;
|
||||
};
|
||||
|
||||
int dm_fs_init(void)
|
||||
@ -119,6 +123,7 @@ int dm_fs_add(struct mapped_device *md)
|
||||
|
||||
pfd->fn = process_table;
|
||||
pfd->minor = MINOR(md->dev);
|
||||
pfd->map = 0;
|
||||
|
||||
if (!(md->pde = create_proc_entry(md->name, S_IRUGO | S_IWUSR,
|
||||
_proc_dir))) {
|
||||
@ -148,6 +153,11 @@ int dm_fs_add(struct mapped_device *md)
|
||||
int dm_fs_remove(struct mapped_device *md)
|
||||
{
|
||||
if (md->pde) {
|
||||
struct pf_data *pfd = (struct pf_data *) md->pde->data;
|
||||
|
||||
if (pfd->map)
|
||||
dm_table_destroy(pfd->map);
|
||||
|
||||
kfree(md->pde->data);
|
||||
remove_proc_entry(md->name, _proc_dir);
|
||||
md->pde = 0;
|
||||
@ -158,7 +168,8 @@ int dm_fs_remove(struct mapped_device *md)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_control(const char *b, const char *e, int minor)
|
||||
static int process_control(const char *b, const char *e, int minor,
|
||||
struct dm_table **map)
|
||||
{
|
||||
const char *wb, *we;
|
||||
char name[64];
|
||||
@ -201,10 +212,12 @@ static int process_control(const char *b, const char *e, int minor)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int process_table(const char *b, const char *e, int minor)
|
||||
static int process_table(const char *b, const char *e, int minor,
|
||||
struct dm_table **map)
|
||||
{
|
||||
const char *wb, *we;
|
||||
struct mapped_device *md = dm_find_by_minor(minor);
|
||||
struct dm_table *table = *map;
|
||||
void *context;
|
||||
int r;
|
||||
|
||||
@ -219,12 +232,15 @@ static int process_table(const char *b, const char *e, int minor)
|
||||
dm_suspend(md);
|
||||
|
||||
/* start loading a table */
|
||||
dm_table_start(md);
|
||||
table = *map = dm_table_create();
|
||||
|
||||
} else if (!tok_cmp("end", b, e)) {
|
||||
/* activate the device ... <evil chuckle> ... */
|
||||
dm_table_complete(md);
|
||||
dm_activate(md);
|
||||
if (table) {
|
||||
dm_table_complete(table);
|
||||
dm_bind(md, table);
|
||||
dm_activate(md);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* add the new entry */
|
||||
@ -253,18 +269,18 @@ static int process_table(const char *b, const char *e, int minor)
|
||||
return -EINVAL;
|
||||
|
||||
/* check there isn't a gap */
|
||||
if ((md->num_targets &&
|
||||
start != md->highs[md->num_targets - 1] + 1) ||
|
||||
(!md->num_targets && start)) {
|
||||
if ((table->num_targets &&
|
||||
start != table->highs[table->num_targets - 1] + 1) ||
|
||||
(!table->num_targets && start)) {
|
||||
WARN("gap in target ranges");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
high = start + (size - 1);
|
||||
if ((r = t->ctr(start, high, md, we, e, &context)))
|
||||
if ((r = t->ctr(start, high, table, we, e, &context)))
|
||||
return r;
|
||||
|
||||
if ((r = dm_table_add_entry(md, high, t->map, context)))
|
||||
if ((r = dm_table_add_entry(table, high, t->map, context)))
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -302,7 +318,7 @@ static int line_splitter(struct file *file, const char *buffer,
|
||||
while((b != e) && *b != '\n')
|
||||
b++;
|
||||
|
||||
if ((r = pfd->fn(lb, b, pfd->minor)))
|
||||
if ((r = pfd->fn(lb, b, pfd->minor, &pfd->map)))
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ static inline ulong div_up(ulong n, ulong size)
|
||||
}
|
||||
|
||||
/* ceiling(log_size(n)) */
|
||||
static uint int_log(ulong base, ulong n)
|
||||
static uint int_log(ulong n, ulong base)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
@ -57,14 +57,14 @@ static uint int_log(ulong base, ulong n)
|
||||
* return the highest key that you could lookup
|
||||
* from the n'th node on level l of the btree.
|
||||
*/
|
||||
static offset_t high(struct mapped_device *md, int l, int n)
|
||||
static offset_t high(struct dm_table *t, int l, int n)
|
||||
{
|
||||
while (1) {
|
||||
if (n >= md->counts[l])
|
||||
if (n >= t->counts[l])
|
||||
return (offset_t) -1;
|
||||
|
||||
if (l == md->depth - 1)
|
||||
return md->index[l][((n + 1) * KEYS_PER_NODE) - 1];
|
||||
if (l == t->depth - 1)
|
||||
return t->index[l][((n + 1) * KEYS_PER_NODE) - 1];
|
||||
|
||||
l++;
|
||||
n = (n + 1) * (KEYS_PER_NODE + 1) - 1;
|
||||
@ -77,15 +77,15 @@ static offset_t high(struct mapped_device *md, int l, int n)
|
||||
* fills in a level of the btree based on the
|
||||
* highs of the level below it.
|
||||
*/
|
||||
static int setup_btree_index(int l, struct mapped_device *md)
|
||||
static int setup_btree_index(int l, struct dm_table *t)
|
||||
{
|
||||
int n, c, cn;
|
||||
|
||||
for (n = 0, cn = 0; n < md->counts[l]; n++) {
|
||||
offset_t *k = md->index[l] + (n * KEYS_PER_NODE);
|
||||
for (n = 0, cn = 0; n < t->counts[l]; n++) {
|
||||
offset_t *k = t->index[l] + (n * KEYS_PER_NODE);
|
||||
|
||||
for (c = 0; c < KEYS_PER_NODE; c++)
|
||||
k[c] = high(md, l + 1, cn++);
|
||||
k[c] = high(t, l + 1, cn++);
|
||||
cn++; /* one extra for the child that's
|
||||
greater than all keys */
|
||||
}
|
||||
@ -93,31 +93,15 @@ static int setup_btree_index(int l, struct mapped_device *md)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dm_table_free(struct mapped_device *md)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < md->depth; i++) {
|
||||
vfree(md->index[i]);
|
||||
md->index[i] = 0;
|
||||
}
|
||||
|
||||
vfree(md->targets);
|
||||
|
||||
md->highs = 0;
|
||||
md->targets = 0;
|
||||
|
||||
md->num_targets = 0;
|
||||
md->num_allocated = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* md->highs, and md->targets are managed as
|
||||
* dynamic arrays during a table load.
|
||||
* highs, and targets are managed as dynamic
|
||||
* arrays during a table load.
|
||||
*/
|
||||
static int alloc_targets(struct mapped_device *md, int num)
|
||||
static int alloc_targets(struct dm_table *t, int num)
|
||||
{
|
||||
offset_t *n_highs;
|
||||
struct target *n_targets;
|
||||
int n = t->num_targets;
|
||||
|
||||
if (!(n_highs = vmalloc(sizeof(*n_highs) * num)))
|
||||
return -ENOMEM;
|
||||
@ -127,93 +111,143 @@ static int alloc_targets(struct mapped_device *md, int num)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (md->num_targets) {
|
||||
memcpy(n_highs, md->highs,
|
||||
sizeof(*n_highs) * md->num_targets);
|
||||
|
||||
memcpy(n_targets, md->targets,
|
||||
sizeof(*n_targets) * md->num_targets);
|
||||
if (n) {
|
||||
memcpy(n_highs, t->highs, sizeof(*n_highs) * n);
|
||||
memcpy(n_targets, t->targets, sizeof(*n_targets) * n);
|
||||
}
|
||||
|
||||
vfree(md->highs);
|
||||
vfree(md->targets);
|
||||
vfree(t->highs);
|
||||
vfree(t->targets);
|
||||
|
||||
md->num_allocated = num;
|
||||
md->highs = n_highs;
|
||||
md->targets = n_targets;
|
||||
t->num_allocated = num;
|
||||
t->highs = n_highs;
|
||||
t->targets = n_targets;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dm_table_start(struct mapped_device *md)
|
||||
struct dm_table *dm_table_create(void)
|
||||
{
|
||||
int r;
|
||||
set_bit(DM_LOADING, &md->state);
|
||||
struct dm_table *t = kmalloc(sizeof(struct dm_table), GFP_NOIO);
|
||||
|
||||
dm_table_free(md);
|
||||
if (!t)
|
||||
return 0;
|
||||
|
||||
/* allocate a single nodes worth to start with */
|
||||
if ((r = alloc_targets(md, KEYS_PER_NODE)))
|
||||
memset(t, 0, sizeof(*t));
|
||||
|
||||
/* allocate a single nodes worth of targets to
|
||||
begin with */
|
||||
if (t && alloc_targets(t, KEYS_PER_NODE)) {
|
||||
kfree(t);
|
||||
t = 0;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void dm_table_destroy(struct dm_table *t)
|
||||
{
|
||||
struct dev_list *d, *n;
|
||||
int i;
|
||||
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
/* free the indexes */
|
||||
for (i = 0; i < t->depth; i++) {
|
||||
vfree(t->index[i]);
|
||||
t->index[i] = 0;
|
||||
}
|
||||
|
||||
/* t->highs was already freed as t->index[t->depth - 1] */
|
||||
vfree(t->targets);
|
||||
kfree(t);
|
||||
|
||||
/* free the device list */
|
||||
for (d = t->devices; d; d = n) {
|
||||
n = d->next;
|
||||
kfree(d);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* checks to see if we need to extend highs or targets
|
||||
*/
|
||||
static inline int check_space(struct dm_table *t)
|
||||
{
|
||||
if (t->num_targets >= t->num_allocated)
|
||||
return alloc_targets(t, t->num_allocated * 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* adds a target to the map
|
||||
*/
|
||||
int dm_table_add_entry(struct dm_table *t, offset_t high,
|
||||
dm_map_fn target, void *private)
|
||||
{
|
||||
int r, n;
|
||||
|
||||
if ((r = check_space(t)))
|
||||
return r;
|
||||
|
||||
n = t->num_targets++;
|
||||
t->highs[n] = high;
|
||||
t->targets[n].map = target;
|
||||
t->targets[n].private = private;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int check_space(struct mapped_device *md)
|
||||
int dm_table_add_device(struct dm_table *t, kdev_t dev)
|
||||
{
|
||||
if (md->num_targets >= md->num_allocated)
|
||||
return alloc_targets(md, md->num_allocated * 2);
|
||||
struct dev_list *d = kmalloc(sizeof(*d), GFP_KERNEL);
|
||||
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
d->dev = dev;
|
||||
d->next = t->devices;
|
||||
t->devices = d;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dm_table_add_entry(struct mapped_device *md, offset_t high,
|
||||
dm_map_fn target, void *context)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = check_space(md)))
|
||||
return r;
|
||||
|
||||
md->highs[md->num_targets] = high;
|
||||
md->targets[md->num_targets].map = target;
|
||||
md->targets[md->num_targets].private = context;
|
||||
md->num_targets++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dm_table_complete(struct mapped_device *md)
|
||||
/*
|
||||
* builds the btree to index the map
|
||||
*/
|
||||
int dm_table_complete(struct dm_table *t)
|
||||
{
|
||||
int i, leaf_nodes;
|
||||
|
||||
clear_bit(DM_LOADING, &md->state);
|
||||
|
||||
/* how many indexes will the btree have ? */
|
||||
leaf_nodes = div_up(md->num_targets, KEYS_PER_NODE);
|
||||
leaf_nodes = div_up(t->num_targets, KEYS_PER_NODE);
|
||||
i = 1 + int_log(leaf_nodes, KEYS_PER_NODE + 1);
|
||||
|
||||
md->depth = i;
|
||||
md->counts[md->depth - 1] = div_up(md->num_targets, KEYS_PER_NODE);
|
||||
/* work out how many nodes are in each layer */
|
||||
t->depth = i;
|
||||
t->counts[t->depth - 1] = div_up(t->num_targets, KEYS_PER_NODE);
|
||||
|
||||
while (--i)
|
||||
md->counts[i - 1] = div_up(md->counts[i], KEYS_PER_NODE + 1);
|
||||
t->counts[i - 1] = div_up(t->counts[i], KEYS_PER_NODE + 1);
|
||||
|
||||
for (i = 0; i < (md->depth - 1); i++) {
|
||||
size_t s = NODE_SIZE * md->counts[i];
|
||||
md->index[i] = vmalloc(s);
|
||||
memset(md->index[i], -1, s);
|
||||
/* allocate memory for the internal nodes */
|
||||
for (i = 0; i < (t->depth - 1); i++) {
|
||||
size_t s = NODE_SIZE * t->counts[i];
|
||||
t->index[i] = vmalloc(s);
|
||||
memset(t->index[i], -1, s);
|
||||
}
|
||||
|
||||
/* bottom layer is easy */
|
||||
md->index[md->depth - 1] = md->highs;
|
||||
/* leaf layer has already been set up */
|
||||
t->index[t->depth - 1] = t->highs;
|
||||
|
||||
/* fill in higher levels */
|
||||
for (i = md->depth - 1; i; i--)
|
||||
setup_btree_index(i - 1, md);
|
||||
for (i = t->depth - 1; i; i--)
|
||||
setup_btree_index(i - 1, t);
|
||||
|
||||
set_bit(DM_LOADED, &md->state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
EXPORT_SYMBOL(dm_table_add_device);
|
||||
|
@ -47,6 +47,9 @@ struct target_type *dm_get_target(const char *name)
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
* register a new target_type.
|
||||
*/
|
||||
int register_map_target(const char *name, dm_ctr_fn ctr,
|
||||
dm_dtr_fn dtr, dm_map_fn map)
|
||||
{
|
||||
@ -82,7 +85,7 @@ int register_map_target(const char *name, dm_ctr_fn ctr,
|
||||
* io-err: always fails an io, useful for bringing
|
||||
* up LV's that have holes in them.
|
||||
*/
|
||||
static int io_err_ctr(offset_t b, offset_t e, struct mapped_device *md,
|
||||
static int io_err_ctr(offset_t b, offset_t e, struct dm_table *t,
|
||||
const char *cb, const char *ce, void **result)
|
||||
{
|
||||
/* this takes no arguments */
|
||||
@ -109,11 +112,13 @@ struct linear_c {
|
||||
int offset; /* FIXME: we need a signed offset type */
|
||||
};
|
||||
|
||||
static int linear_ctr(offset_t low, offset_t high, struct mapped_device *md,
|
||||
/*
|
||||
* construct a linear mapping.
|
||||
* <major> <minor> <offset>
|
||||
*/
|
||||
static int linear_ctr(offset_t low, offset_t high, struct dm_table *t,
|
||||
const char *cb, const char *ce, void **result)
|
||||
{
|
||||
/* <major> <minor> <offset> */
|
||||
|
||||
struct linear_c *lc;
|
||||
unsigned int major, minor, start;
|
||||
int r;
|
||||
@ -135,7 +140,7 @@ static int linear_ctr(offset_t low, offset_t high, struct mapped_device *md,
|
||||
lc->dev = MKDEV((int) major, (int) minor);
|
||||
lc->offset = (int) start - (int) low;
|
||||
|
||||
if ((r = dm_add_device(md, lc->dev))) {
|
||||
if ((r = dm_table_add_device(t, lc->dev))) {
|
||||
kfree(lc);
|
||||
return r;
|
||||
}
|
||||
|
@ -63,23 +63,12 @@ static int _block_size[MAX_DEVICES];
|
||||
static int _blksize_size[MAX_DEVICES];
|
||||
static int _hardsect_size[MAX_DEVICES];
|
||||
|
||||
static int blk_open(struct inode *inode, struct file *file);
|
||||
static int blk_close(struct inode *inode, struct file *file);
|
||||
static int blk_ioctl(struct inode *inode, struct file *file,
|
||||
uint command, ulong a);
|
||||
|
||||
struct block_device_operations dm_blk_dops = {
|
||||
open: blk_open,
|
||||
release: blk_close,
|
||||
ioctl: blk_ioctl
|
||||
};
|
||||
|
||||
static int request(request_queue_t *q, int rw, struct buffer_head *bh);
|
||||
|
||||
/*
|
||||
* setup and teardown the driver
|
||||
*/
|
||||
static int init_dm(void)
|
||||
static int dm_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -112,7 +101,7 @@ static int init_dm(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exit_dm(void)
|
||||
static void dm_exit(void)
|
||||
{
|
||||
if(kmem_cache_shrink(_io_hook_cache))
|
||||
WARN("it looks like there are still some io_hooks allocated");
|
||||
@ -252,6 +241,11 @@ inline static void free_deferred(struct deferred_io *di)
|
||||
kfree(di);
|
||||
}
|
||||
|
||||
/*
|
||||
* bh->b_end_io routine that decrements the
|
||||
* pending count and then calls the original
|
||||
* bh->b_end_io fn.
|
||||
*/
|
||||
static void dec_pending(struct buffer_head *bh, int uptodate)
|
||||
{
|
||||
struct io_hook *ih = bh->b_private;
|
||||
@ -267,6 +261,9 @@ static void dec_pending(struct buffer_head *bh, int uptodate)
|
||||
bh->b_end_io(bh, uptodate);
|
||||
}
|
||||
|
||||
/*
|
||||
* add the bh to the list of deferred io.
|
||||
*/
|
||||
static int queue_io(struct mapped_device *md, struct buffer_head *bh, int rw)
|
||||
{
|
||||
struct deferred_io *di = alloc_deferred();
|
||||
@ -289,15 +286,17 @@ static int queue_io(struct mapped_device *md, struct buffer_head *bh, int rw)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* do the bh mapping for a given leaf
|
||||
*/
|
||||
inline static int __map_buffer(struct mapped_device *md,
|
||||
struct buffer_head *bh, int node)
|
||||
struct buffer_head *bh, int leaf)
|
||||
{
|
||||
dm_map_fn fn;
|
||||
void *context;
|
||||
struct io_hook *ih = 0;
|
||||
int r;
|
||||
struct target *ti = md->targets + node;
|
||||
struct target *ti = md->map->targets + leaf;
|
||||
|
||||
fn = ti->map;
|
||||
context = ti->private;
|
||||
@ -334,15 +333,17 @@ inline static int __map_buffer(struct mapped_device *md,
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline static int __find_node(struct mapped_device *md, struct buffer_head *bh)
|
||||
/*
|
||||
* search the btree for the correct target.
|
||||
*/
|
||||
inline static int __find_node(struct dm_table *t, struct buffer_head *bh)
|
||||
{
|
||||
int i = 0, l, r = 0;
|
||||
offset_t *node;
|
||||
|
||||
/* search the btree for the correct target */
|
||||
for (l = 0; l < md->depth; l++) {
|
||||
for (l = 0; l < t->depth; l++) {
|
||||
r = ((KEYS_PER_NODE + 1) * r) + i;
|
||||
node = md->index[l] + (r * KEYS_PER_NODE);
|
||||
node = t->index[l] + (r * KEYS_PER_NODE);
|
||||
|
||||
for (i = 0; i < KEYS_PER_NODE; i++)
|
||||
if (node[i] >= bh->b_rsector)
|
||||
@ -363,7 +364,7 @@ static int request(request_queue_t *q, int rw, struct buffer_head *bh)
|
||||
rl;
|
||||
md = _devs[minor];
|
||||
|
||||
if (!md || !test_bit(DM_LOADED, &md->state))
|
||||
if (!md || !md->map)
|
||||
goto bad;
|
||||
|
||||
/* if we're suspended we have to queue this io for later */
|
||||
@ -380,7 +381,7 @@ static int request(request_queue_t *q, int rw, struct buffer_head *bh)
|
||||
rl; /* FIXME: there's still a race here */
|
||||
}
|
||||
|
||||
if (!__map_buffer(md, bh, __find_node(md, bh)))
|
||||
if (!__map_buffer(md, bh, __find_node(md->map, bh)))
|
||||
goto bad;
|
||||
|
||||
ru;
|
||||
@ -394,6 +395,10 @@ static int request(request_queue_t *q, int rw, struct buffer_head *bh)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* see if the device with a specific minor # is
|
||||
* free.
|
||||
*/
|
||||
static inline int __specific_dev(int minor)
|
||||
{
|
||||
if (minor > MAX_DEVICES) {
|
||||
@ -407,6 +412,9 @@ static inline int __specific_dev(int minor)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* find the first free device.
|
||||
*/
|
||||
static inline int __any_old_dev(void)
|
||||
{
|
||||
int i;
|
||||
@ -418,6 +426,9 @@ static inline int __any_old_dev(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate and initialise a blank device.
|
||||
*/
|
||||
static struct mapped_device *alloc_dev(int minor)
|
||||
{
|
||||
struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);
|
||||
@ -445,16 +456,10 @@ static struct mapped_device *alloc_dev(int minor)
|
||||
return md;
|
||||
}
|
||||
|
||||
static inline struct mapped_device *__find_by_name(const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_DEVICES; i++)
|
||||
if (_devs[i] && !strcmp(_devs[i]->name, name))
|
||||
return _devs[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* open a device so we can use it as a map
|
||||
* destination.
|
||||
*/
|
||||
static int open_dev(struct dev_list *d)
|
||||
{
|
||||
int err;
|
||||
@ -470,6 +475,9 @@ static int open_dev(struct dev_list *d)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* close a device that we've been using.
|
||||
*/
|
||||
static void close_dev(struct dev_list *d)
|
||||
{
|
||||
blkdev_put(d->bd, BDEV_FILE);
|
||||
@ -477,18 +485,14 @@ static void close_dev(struct dev_list *d)
|
||||
d->bd = 0;
|
||||
}
|
||||
|
||||
static int __find_hardsect_size(struct mapped_device *md)
|
||||
static inline struct mapped_device *__find_by_name(const char *name)
|
||||
{
|
||||
int r = INT_MAX, s;
|
||||
struct dev_list *dl;
|
||||
int i;
|
||||
for (i = 0; i < MAX_DEVICES; i++)
|
||||
if (_devs[i] && !strcmp(_devs[i]->name, name))
|
||||
return _devs[i];
|
||||
|
||||
for (dl = md->devices; dl; dl = dl->next) {
|
||||
s = get_hardsect_size(dl->dev);
|
||||
if (s < r)
|
||||
r = s;
|
||||
}
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mapped_device *dm_find_by_name(const char *name)
|
||||
@ -513,6 +517,9 @@ struct mapped_device *dm_find_by_minor(int minor)
|
||||
return md;
|
||||
}
|
||||
|
||||
/*
|
||||
* constructor for a new device
|
||||
*/
|
||||
int dm_create(const char *name, int minor)
|
||||
{
|
||||
int r;
|
||||
@ -544,10 +551,14 @@ int dm_create(const char *name, int minor)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* destructor for the device. md->map is
|
||||
* deliberately not destroyed, dm-fs should manage
|
||||
* table objects.
|
||||
*/
|
||||
int dm_remove(const char *name)
|
||||
{
|
||||
struct mapped_device *md;
|
||||
struct dev_list *d, *n;
|
||||
int minor, r;
|
||||
|
||||
wl;
|
||||
@ -566,12 +577,6 @@ int dm_remove(const char *name)
|
||||
return r;
|
||||
}
|
||||
|
||||
dm_table_free(md);
|
||||
for (d = md->devices; d; d = n) {
|
||||
n = d->next;
|
||||
kfree(d);
|
||||
}
|
||||
|
||||
minor = MINOR(md->dev);
|
||||
kfree(md);
|
||||
_devs[minor] = 0;
|
||||
@ -580,20 +585,57 @@ int dm_remove(const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dm_add_device(struct mapped_device *md, kdev_t dev)
|
||||
/*
|
||||
* the hardsect size for a mapped device is the
|
||||
* smallest hard sect size from the devices it
|
||||
* maps onto.
|
||||
*/
|
||||
static int __find_hardsect_size(struct dev_list *dl)
|
||||
{
|
||||
struct dev_list *d = kmalloc(sizeof(*d), GFP_KERNEL);
|
||||
int result = INT_MAX, size;
|
||||
|
||||
if (!d)
|
||||
return -EINVAL;
|
||||
while(dl) {
|
||||
size = get_hardsect_size(dl->dev);
|
||||
if (size < result)
|
||||
result = size;
|
||||
dl = dl->next;
|
||||
}
|
||||
|
||||
d->dev = dev;
|
||||
d->next = md->devices;
|
||||
md->devices = d;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* bind a table to the device, the device must not
|
||||
* be active, though it could have another table
|
||||
* aready bound.
|
||||
*/
|
||||
int dm_bind(struct mapped_device *md, struct dm_table *t)
|
||||
{
|
||||
int minor = MINOR(md->dev);
|
||||
|
||||
wl;
|
||||
if (is_active(md)) {
|
||||
wu;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
md->map = t;
|
||||
|
||||
_block_size[minor] = (t->highs[t->num_targets - 1] + 1) >> 1;
|
||||
|
||||
/* FIXME: block size depends on the mapping table */
|
||||
_blksize_size[minor] = BLOCK_SIZE;
|
||||
_hardsect_size[minor] = __find_hardsect_size(t->devices);
|
||||
register_disk(NULL, md->dev, 1, &dm_blk_dops, _block_size[minor]);
|
||||
wu;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* requeue the deferred buffer_heads by calling
|
||||
* generic_make_request.
|
||||
*/
|
||||
static void __flush_deferred_io(struct mapped_device *md)
|
||||
{
|
||||
struct deferred_io *c, *n;
|
||||
@ -605,9 +647,14 @@ static void __flush_deferred_io(struct mapped_device *md)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* make the device available for use, if was
|
||||
* previously suspended rather than newly created
|
||||
* then all queued io is flushed
|
||||
*/
|
||||
int dm_activate(struct mapped_device *md)
|
||||
{
|
||||
int ret, minor;
|
||||
int ret;
|
||||
struct dev_list *d, *od;
|
||||
|
||||
wl;
|
||||
@ -617,27 +664,17 @@ int dm_activate(struct mapped_device *md)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!md->num_targets) {
|
||||
if (!md->map) {
|
||||
wu;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* open all the devices */
|
||||
for (d = md->devices; d; d = d->next)
|
||||
for (d = md->map->devices; d; d = d->next)
|
||||
if ((ret = open_dev(d)))
|
||||
goto bad;
|
||||
|
||||
minor = MINOR(md->dev);
|
||||
|
||||
_block_size[minor] = (md->highs[md->num_targets - 1] + 1) >> 1;
|
||||
_blksize_size[minor] = BLOCK_SIZE; /* FIXME: this depends on
|
||||
the mapping table */
|
||||
_hardsect_size[minor] = __find_hardsect_size(md);
|
||||
|
||||
register_disk(NULL, md->dev, 1, &dm_blk_dops, _block_size[minor]);
|
||||
|
||||
set_bit(DM_ACTIVE, &md->state);
|
||||
|
||||
__flush_deferred_io(md);
|
||||
wu;
|
||||
|
||||
@ -645,17 +682,27 @@ int dm_activate(struct mapped_device *md)
|
||||
|
||||
bad:
|
||||
od = d;
|
||||
for (d = md->devices; d != od; d = d->next)
|
||||
for (d = md->map->devices; d != od; d = d->next)
|
||||
close_dev(d);
|
||||
ru;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* we need to be able to change a mapping table
|
||||
* under a mounted filesystem. for example we
|
||||
* might want to move some data in the background.
|
||||
* Before the table can be swapped with
|
||||
* dm_bind_table, dm_suspend must be called to
|
||||
* flush any in flight buffer_heads and ensure
|
||||
* that any further io gets deferred.
|
||||
*/
|
||||
void dm_suspend(struct mapped_device *md)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
struct dev_list *d;
|
||||
|
||||
if (!is_active(md))
|
||||
return;
|
||||
|
||||
@ -676,7 +723,7 @@ void dm_suspend(struct mapped_device *md)
|
||||
remove_wait_queue(&md->wait, &wait);
|
||||
|
||||
/* close all the devices */
|
||||
for (d = md->devices; d; d = d->next)
|
||||
for (d = md->map->devices; d; d = d->next)
|
||||
close_dev(d);
|
||||
|
||||
clear_bit(DM_ACTIVE, &md->state);
|
||||
@ -684,11 +731,17 @@ void dm_suspend(struct mapped_device *md)
|
||||
}
|
||||
|
||||
|
||||
struct block_device_operations dm_blk_dops = {
|
||||
open: blk_open,
|
||||
release: blk_close,
|
||||
ioctl: blk_ioctl
|
||||
};
|
||||
|
||||
/*
|
||||
* module hooks
|
||||
*/
|
||||
module_init(init_dm);
|
||||
module_exit(exit_dm);
|
||||
module_init(dm_init);
|
||||
module_exit(dm_exit);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
@ -137,9 +137,8 @@
|
||||
#define DM_NAME_LEN 64
|
||||
|
||||
enum {
|
||||
DM_LOADED = 0,
|
||||
DM_LOADING,
|
||||
DM_ACTIVE,
|
||||
DM_BOUND = 0, /* device has been bound to a table */
|
||||
DM_ACTIVE, /* device is running */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -182,6 +181,24 @@ struct target {
|
||||
void *private;
|
||||
};
|
||||
|
||||
/*
|
||||
* the btree
|
||||
*/
|
||||
struct dm_table {
|
||||
/* btree table */
|
||||
int depth;
|
||||
int counts[MAX_DEPTH]; /* in nodes */
|
||||
offset_t *index[MAX_DEPTH];
|
||||
|
||||
int num_targets;
|
||||
int num_allocated;
|
||||
offset_t *highs;
|
||||
struct target *targets;
|
||||
|
||||
/* a list of devices used by this table */
|
||||
struct dev_list *devices;
|
||||
};
|
||||
|
||||
/*
|
||||
* the actual device struct
|
||||
*/
|
||||
@ -198,46 +215,40 @@ struct mapped_device {
|
||||
/* a list of io's that arrived while we were suspended */
|
||||
struct deferred_io *deferred;
|
||||
|
||||
/* btree table */
|
||||
int depth;
|
||||
int counts[MAX_DEPTH]; /* in nodes */
|
||||
offset_t *index[MAX_DEPTH];
|
||||
|
||||
int num_targets;
|
||||
int num_allocated;
|
||||
offset_t *highs;
|
||||
struct target *targets;
|
||||
struct dm_table *map;
|
||||
|
||||
/* used by dm-fs.c */
|
||||
devfs_handle_t devfs_entry;
|
||||
struct proc_dir_entry *pde;
|
||||
|
||||
/* a list of devices used by this md */
|
||||
struct dev_list *devices;
|
||||
};
|
||||
|
||||
extern struct block_device_operations dm_blk_dops;
|
||||
|
||||
|
||||
/* dm-target.c */
|
||||
int dm_target_init(void);
|
||||
struct target_type *dm_get_target(const char *name);
|
||||
|
||||
|
||||
/* dm.c */
|
||||
struct mapped_device *dm_find_by_name(const char *name);
|
||||
struct mapped_device *dm_find_by_minor(int minor);
|
||||
|
||||
int dm_create(const char *name, int minor);
|
||||
int dm_remove(const char *name);
|
||||
|
||||
int dm_bind(struct mapped_device *md, struct dm_table *t);
|
||||
int dm_activate(struct mapped_device *md);
|
||||
void dm_suspend(struct mapped_device *md);
|
||||
|
||||
|
||||
/* dm-table.c */
|
||||
int dm_table_start(struct mapped_device *md);
|
||||
int dm_table_add_entry(struct mapped_device *md, offset_t high,
|
||||
dm_map_fn target, void *context);
|
||||
int dm_table_complete(struct mapped_device *md);
|
||||
void dm_table_free(struct mapped_device *md);
|
||||
struct dm_table *dm_table_create(void);
|
||||
void dm_table_destroy(struct dm_table *t);
|
||||
|
||||
int dm_table_add_entry(struct dm_table *t, offset_t high,
|
||||
dm_map_fn target, void *private);
|
||||
int dm_table_complete(struct dm_table *t);
|
||||
|
||||
|
||||
/* dm-fs.c */
|
||||
int dm_fs_init(void);
|
||||
|
Loading…
Reference in New Issue
Block a user