1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +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:
Joe Thornber 2001-08-31 15:13:33 +00:00
parent 4183d3fe6c
commit 0f29dc2f2d
6 changed files with 321 additions and 199 deletions

View File

@ -35,11 +35,11 @@
/* FIXME: Use value from local range for now, for co-existence with LVM 1 */ /* FIXME: Use value from local range for now, for co-existence with LVM 1 */
#define DM_BLK_MAJOR 124 #define DM_BLK_MAJOR 124
struct mapped_device; struct dm_table;
typedef unsigned int offset_t; typedef unsigned int offset_t;
/* constructor, destructor and map fn types */ /* 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); const char *cb, const char *ce, void **result);
typedef void (*dm_dtr_fn)(void *c); typedef void (*dm_dtr_fn)(void *c);
typedef int (*dm_map_fn)(struct buffer_head *bh, void *context); 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, int register_map_target(const char *name, dm_ctr_fn ctr, dm_dtr_fn dtr,
dm_map_fn map); dm_map_fn map);
/* contructors should call this to make sure any destination devices
are handled correctly (ie. opened/closed) */ /* contructors should call this to make sure any
int dm_add_device(struct mapped_device *md, kdev_t dev); * destination devices are handled correctly
* (ie. opened/closed).
*/
int dm_table_add_device(struct dm_table *t, kdev_t dev);
#endif #endif
#endif #endif

View File

@ -49,21 +49,25 @@ static struct proc_dir_entry *_control;
static devfs_handle_t _dev_dir; 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, static int line_splitter(struct file *file, const char *buffer,
unsigned long count, void *data); 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, static int get_word(const char *b, const char *e,
const char **wb, const char **we); const char **wb, const char **we);
static int tok_cmp(const char *str, const char *b, const char *e); static int tok_cmp(const char *str, const char *b, const char *e);
static void tok_cpy(char *dest, size_t max, static void tok_cpy(char *dest, size_t max,
const char *b, const char *e); 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 { struct pf_data {
process_fn fn; process_fn fn;
int minor; int minor;
struct dm_table *map;
}; };
int dm_fs_init(void) int dm_fs_init(void)
@ -119,6 +123,7 @@ int dm_fs_add(struct mapped_device *md)
pfd->fn = process_table; pfd->fn = process_table;
pfd->minor = MINOR(md->dev); pfd->minor = MINOR(md->dev);
pfd->map = 0;
if (!(md->pde = create_proc_entry(md->name, S_IRUGO | S_IWUSR, if (!(md->pde = create_proc_entry(md->name, S_IRUGO | S_IWUSR,
_proc_dir))) { _proc_dir))) {
@ -148,6 +153,11 @@ int dm_fs_add(struct mapped_device *md)
int dm_fs_remove(struct mapped_device *md) int dm_fs_remove(struct mapped_device *md)
{ {
if (md->pde) { 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); kfree(md->pde->data);
remove_proc_entry(md->name, _proc_dir); remove_proc_entry(md->name, _proc_dir);
md->pde = 0; md->pde = 0;
@ -158,7 +168,8 @@ int dm_fs_remove(struct mapped_device *md)
return 0; 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; const char *wb, *we;
char name[64]; char name[64];
@ -201,10 +212,12 @@ static int process_control(const char *b, const char *e, int minor)
return -EINVAL; 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; const char *wb, *we;
struct mapped_device *md = dm_find_by_minor(minor); struct mapped_device *md = dm_find_by_minor(minor);
struct dm_table *table = *map;
void *context; void *context;
int r; int r;
@ -219,12 +232,15 @@ static int process_table(const char *b, const char *e, int minor)
dm_suspend(md); dm_suspend(md);
/* start loading a table */ /* start loading a table */
dm_table_start(md); table = *map = dm_table_create();
} else if (!tok_cmp("end", b, e)) { } else if (!tok_cmp("end", b, e)) {
/* activate the device ... <evil chuckle> ... */ /* activate the device ... <evil chuckle> ... */
dm_table_complete(md); if (table) {
dm_activate(md); dm_table_complete(table);
dm_bind(md, table);
dm_activate(md);
}
} else { } else {
/* add the new entry */ /* add the new entry */
@ -253,18 +269,18 @@ static int process_table(const char *b, const char *e, int minor)
return -EINVAL; return -EINVAL;
/* check there isn't a gap */ /* check there isn't a gap */
if ((md->num_targets && if ((table->num_targets &&
start != md->highs[md->num_targets - 1] + 1) || start != table->highs[table->num_targets - 1] + 1) ||
(!md->num_targets && start)) { (!table->num_targets && start)) {
WARN("gap in target ranges"); WARN("gap in target ranges");
return -EINVAL; return -EINVAL;
} }
high = start + (size - 1); 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; 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; return r;
} }
@ -302,7 +318,7 @@ static int line_splitter(struct file *file, const char *buffer,
while((b != e) && *b != '\n') while((b != e) && *b != '\n')
b++; b++;
if ((r = pfd->fn(lb, b, pfd->minor))) if ((r = pfd->fn(lb, b, pfd->minor, &pfd->map)))
return r; return r;
} }

View File

@ -41,7 +41,7 @@ static inline ulong div_up(ulong n, ulong size)
} }
/* ceiling(log_size(n)) */ /* ceiling(log_size(n)) */
static uint int_log(ulong base, ulong n) static uint int_log(ulong n, ulong base)
{ {
int result = 0; int result = 0;
@ -57,14 +57,14 @@ static uint int_log(ulong base, ulong n)
* return the highest key that you could lookup * return the highest key that you could lookup
* from the n'th node on level l of the btree. * 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) { while (1) {
if (n >= md->counts[l]) if (n >= t->counts[l])
return (offset_t) -1; return (offset_t) -1;
if (l == md->depth - 1) if (l == t->depth - 1)
return md->index[l][((n + 1) * KEYS_PER_NODE) - 1]; return t->index[l][((n + 1) * KEYS_PER_NODE) - 1];
l++; l++;
n = (n + 1) * (KEYS_PER_NODE + 1) - 1; 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 * fills in a level of the btree based on the
* highs of the level below it. * 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; int n, c, cn;
for (n = 0, cn = 0; n < md->counts[l]; n++) { for (n = 0, cn = 0; n < t->counts[l]; n++) {
offset_t *k = md->index[l] + (n * KEYS_PER_NODE); offset_t *k = t->index[l] + (n * KEYS_PER_NODE);
for (c = 0; c < KEYS_PER_NODE; c++) 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 cn++; /* one extra for the child that's
greater than all keys */ greater than all keys */
} }
@ -93,31 +93,15 @@ static int setup_btree_index(int l, struct mapped_device *md)
return 0; 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 * highs, and targets are managed as dynamic
* dynamic arrays during a table load. * 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; offset_t *n_highs;
struct target *n_targets; struct target *n_targets;
int n = t->num_targets;
if (!(n_highs = vmalloc(sizeof(*n_highs) * num))) if (!(n_highs = vmalloc(sizeof(*n_highs) * num)))
return -ENOMEM; return -ENOMEM;
@ -127,93 +111,143 @@ static int alloc_targets(struct mapped_device *md, int num)
return -ENOMEM; return -ENOMEM;
} }
if (md->num_targets) { if (n) {
memcpy(n_highs, md->highs, memcpy(n_highs, t->highs, sizeof(*n_highs) * n);
sizeof(*n_highs) * md->num_targets); memcpy(n_targets, t->targets, sizeof(*n_targets) * n);
memcpy(n_targets, md->targets,
sizeof(*n_targets) * md->num_targets);
} }
vfree(md->highs); vfree(t->highs);
vfree(md->targets); vfree(t->targets);
md->num_allocated = num; t->num_allocated = num;
md->highs = n_highs; t->highs = n_highs;
md->targets = n_targets; t->targets = n_targets;
return 0; return 0;
} }
int dm_table_start(struct mapped_device *md) struct dm_table *dm_table_create(void)
{ {
int r; struct dm_table *t = kmalloc(sizeof(struct dm_table), GFP_NOIO);
set_bit(DM_LOADING, &md->state);
dm_table_free(md); if (!t)
return 0;
/* allocate a single nodes worth to start with */ memset(t, 0, sizeof(*t));
if ((r = alloc_targets(md, KEYS_PER_NODE)))
/* 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; return r;
n = t->num_targets++;
t->highs[n] = high;
t->targets[n].map = target;
t->targets[n].private = private;
return 0; 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) struct dev_list *d = kmalloc(sizeof(*d), GFP_KERNEL);
return alloc_targets(md, md->num_allocated * 2);
if (!d)
return -ENOMEM;
d->dev = dev;
d->next = t->devices;
t->devices = d;
return 0; return 0;
} }
int dm_table_add_entry(struct mapped_device *md, offset_t high, /*
dm_map_fn target, void *context) * builds the btree to index the map
{ */
int r; int dm_table_complete(struct dm_table *t)
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)
{ {
int i, leaf_nodes; int i, leaf_nodes;
clear_bit(DM_LOADING, &md->state);
/* how many indexes will the btree have ? */ /* 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); i = 1 + int_log(leaf_nodes, KEYS_PER_NODE + 1);
md->depth = i; /* work out how many nodes are in each layer */
md->counts[md->depth - 1] = div_up(md->num_targets, KEYS_PER_NODE); t->depth = i;
t->counts[t->depth - 1] = div_up(t->num_targets, KEYS_PER_NODE);
while (--i) 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++) { /* allocate memory for the internal nodes */
size_t s = NODE_SIZE * md->counts[i]; for (i = 0; i < (t->depth - 1); i++) {
md->index[i] = vmalloc(s); size_t s = NODE_SIZE * t->counts[i];
memset(md->index[i], -1, s); t->index[i] = vmalloc(s);
memset(t->index[i], -1, s);
} }
/* bottom layer is easy */ /* leaf layer has already been set up */
md->index[md->depth - 1] = md->highs; t->index[t->depth - 1] = t->highs;
/* fill in higher levels */ /* fill in higher levels */
for (i = md->depth - 1; i; i--) for (i = t->depth - 1; i; i--)
setup_btree_index(i - 1, md); setup_btree_index(i - 1, t);
set_bit(DM_LOADED, &md->state);
return 0; return 0;
} }
EXPORT_SYMBOL(dm_table_add_device);

View File

@ -47,6 +47,9 @@ struct target_type *dm_get_target(const char *name)
return t; return t;
} }
/*
* register a new target_type.
*/
int register_map_target(const char *name, dm_ctr_fn ctr, int register_map_target(const char *name, dm_ctr_fn ctr,
dm_dtr_fn dtr, dm_map_fn map) 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 * io-err: always fails an io, useful for bringing
* up LV's that have holes in them. * 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) const char *cb, const char *ce, void **result)
{ {
/* this takes no arguments */ /* this takes no arguments */
@ -109,11 +112,13 @@ struct linear_c {
int offset; /* FIXME: we need a signed offset type */ 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) const char *cb, const char *ce, void **result)
{ {
/* <major> <minor> <offset> */
struct linear_c *lc; struct linear_c *lc;
unsigned int major, minor, start; unsigned int major, minor, start;
int r; 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->dev = MKDEV((int) major, (int) minor);
lc->offset = (int) start - (int) low; 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); kfree(lc);
return r; return r;
} }

View File

@ -63,23 +63,12 @@ static int _block_size[MAX_DEVICES];
static int _blksize_size[MAX_DEVICES]; static int _blksize_size[MAX_DEVICES];
static int _hardsect_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); static int request(request_queue_t *q, int rw, struct buffer_head *bh);
/* /*
* setup and teardown the driver * setup and teardown the driver
*/ */
static int init_dm(void) static int dm_init(void)
{ {
int ret; int ret;
@ -112,7 +101,7 @@ static int init_dm(void)
return 0; return 0;
} }
static void exit_dm(void) static void dm_exit(void)
{ {
if(kmem_cache_shrink(_io_hook_cache)) if(kmem_cache_shrink(_io_hook_cache))
WARN("it looks like there are still some io_hooks allocated"); 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); 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) static void dec_pending(struct buffer_head *bh, int uptodate)
{ {
struct io_hook *ih = bh->b_private; 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); 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) static int queue_io(struct mapped_device *md, struct buffer_head *bh, int rw)
{ {
struct deferred_io *di = alloc_deferred(); 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; return 1;
} }
/*
* do the bh mapping for a given leaf
*/
inline static int __map_buffer(struct mapped_device *md, 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; dm_map_fn fn;
void *context; void *context;
struct io_hook *ih = 0; struct io_hook *ih = 0;
int r; int r;
struct target *ti = md->targets + node; struct target *ti = md->map->targets + leaf;
fn = ti->map; fn = ti->map;
context = ti->private; context = ti->private;
@ -334,15 +333,17 @@ inline static int __map_buffer(struct mapped_device *md,
return 1; 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; int i = 0, l, r = 0;
offset_t *node; offset_t *node;
/* search the btree for the correct target */ for (l = 0; l < t->depth; l++) {
for (l = 0; l < md->depth; l++) {
r = ((KEYS_PER_NODE + 1) * r) + i; 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++) for (i = 0; i < KEYS_PER_NODE; i++)
if (node[i] >= bh->b_rsector) if (node[i] >= bh->b_rsector)
@ -363,7 +364,7 @@ static int request(request_queue_t *q, int rw, struct buffer_head *bh)
rl; rl;
md = _devs[minor]; md = _devs[minor];
if (!md || !test_bit(DM_LOADED, &md->state)) if (!md || !md->map)
goto bad; goto bad;
/* if we're suspended we have to queue this io for later */ /* 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 */ 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; goto bad;
ru; ru;
@ -394,6 +395,10 @@ static int request(request_queue_t *q, int rw, struct buffer_head *bh)
return 0; return 0;
} }
/*
* see if the device with a specific minor # is
* free.
*/
static inline int __specific_dev(int minor) static inline int __specific_dev(int minor)
{ {
if (minor > MAX_DEVICES) { if (minor > MAX_DEVICES) {
@ -407,6 +412,9 @@ static inline int __specific_dev(int minor)
return -1; return -1;
} }
/*
* find the first free device.
*/
static inline int __any_old_dev(void) static inline int __any_old_dev(void)
{ {
int i; int i;
@ -418,6 +426,9 @@ static inline int __any_old_dev(void)
return -1; return -1;
} }
/*
* allocate and initialise a blank device.
*/
static struct mapped_device *alloc_dev(int minor) static struct mapped_device *alloc_dev(int minor)
{ {
struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL); struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);
@ -445,16 +456,10 @@ static struct mapped_device *alloc_dev(int minor)
return md; return md;
} }
static inline struct mapped_device *__find_by_name(const char *name) /*
{ * open a device so we can use it as a map
int i; * destination.
for (i = 0; i < MAX_DEVICES; i++) */
if (_devs[i] && !strcmp(_devs[i]->name, name))
return _devs[i];
return 0;
}
static int open_dev(struct dev_list *d) static int open_dev(struct dev_list *d)
{ {
int err; int err;
@ -470,6 +475,9 @@ static int open_dev(struct dev_list *d)
return 0; return 0;
} }
/*
* close a device that we've been using.
*/
static void close_dev(struct dev_list *d) static void close_dev(struct dev_list *d)
{ {
blkdev_put(d->bd, BDEV_FILE); blkdev_put(d->bd, BDEV_FILE);
@ -477,18 +485,14 @@ static void close_dev(struct dev_list *d)
d->bd = 0; 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; int i;
struct dev_list *dl; 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) { return 0;
s = get_hardsect_size(dl->dev);
if (s < r)
r = s;
}
return r;
} }
struct mapped_device *dm_find_by_name(const char *name) 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; return md;
} }
/*
* constructor for a new device
*/
int dm_create(const char *name, int minor) int dm_create(const char *name, int minor)
{ {
int r; int r;
@ -544,10 +551,14 @@ int dm_create(const char *name, int minor)
return 0; return 0;
} }
/*
* destructor for the device. md->map is
* deliberately not destroyed, dm-fs should manage
* table objects.
*/
int dm_remove(const char *name) int dm_remove(const char *name)
{ {
struct mapped_device *md; struct mapped_device *md;
struct dev_list *d, *n;
int minor, r; int minor, r;
wl; wl;
@ -566,12 +577,6 @@ int dm_remove(const char *name)
return r; return r;
} }
dm_table_free(md);
for (d = md->devices; d; d = n) {
n = d->next;
kfree(d);
}
minor = MINOR(md->dev); minor = MINOR(md->dev);
kfree(md); kfree(md);
_devs[minor] = 0; _devs[minor] = 0;
@ -580,20 +585,57 @@ int dm_remove(const char *name)
return 0; 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) while(dl) {
return -EINVAL; size = get_hardsect_size(dl->dev);
if (size < result)
result = size;
dl = dl->next;
}
d->dev = dev; return result;
d->next = md->devices; }
md->devices = d;
/*
* 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; return 0;
} }
/*
* requeue the deferred buffer_heads by calling
* generic_make_request.
*/
static void __flush_deferred_io(struct mapped_device *md) static void __flush_deferred_io(struct mapped_device *md)
{ {
struct deferred_io *c, *n; 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 dm_activate(struct mapped_device *md)
{ {
int ret, minor; int ret;
struct dev_list *d, *od; struct dev_list *d, *od;
wl; wl;
@ -617,27 +664,17 @@ int dm_activate(struct mapped_device *md)
return 0; return 0;
} }
if (!md->num_targets) { if (!md->map) {
wu; wu;
return -ENXIO; return -ENXIO;
} }
/* open all the devices */ /* 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))) if ((ret = open_dev(d)))
goto bad; 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); set_bit(DM_ACTIVE, &md->state);
__flush_deferred_io(md); __flush_deferred_io(md);
wu; wu;
@ -645,17 +682,27 @@ int dm_activate(struct mapped_device *md)
bad: bad:
od = d; od = d;
for (d = md->devices; d != od; d = d->next) for (d = md->map->devices; d != od; d = d->next)
close_dev(d); close_dev(d);
ru; ru;
return ret; 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) void dm_suspend(struct mapped_device *md)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
struct dev_list *d; struct dev_list *d;
if (!is_active(md)) if (!is_active(md))
return; return;
@ -676,7 +723,7 @@ void dm_suspend(struct mapped_device *md)
remove_wait_queue(&md->wait, &wait); remove_wait_queue(&md->wait, &wait);
/* close all the devices */ /* close all the devices */
for (d = md->devices; d; d = d->next) for (d = md->map->devices; d; d = d->next)
close_dev(d); close_dev(d);
clear_bit(DM_ACTIVE, &md->state); 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 hooks
*/ */
module_init(init_dm); module_init(dm_init);
module_exit(exit_dm); module_exit(dm_exit);
/* /*
* Local variables: * Local variables:

View File

@ -137,9 +137,8 @@
#define DM_NAME_LEN 64 #define DM_NAME_LEN 64
enum { enum {
DM_LOADED = 0, DM_BOUND = 0, /* device has been bound to a table */
DM_LOADING, DM_ACTIVE, /* device is running */
DM_ACTIVE,
}; };
/* /*
@ -182,6 +181,24 @@ struct target {
void *private; 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 * the actual device struct
*/ */
@ -198,46 +215,40 @@ struct mapped_device {
/* a list of io's that arrived while we were suspended */ /* a list of io's that arrived while we were suspended */
struct deferred_io *deferred; struct deferred_io *deferred;
/* btree table */ struct dm_table *map;
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;
/* used by dm-fs.c */ /* used by dm-fs.c */
devfs_handle_t devfs_entry; devfs_handle_t devfs_entry;
struct proc_dir_entry *pde; 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; extern struct block_device_operations dm_blk_dops;
/* dm-target.c */ /* dm-target.c */
int dm_target_init(void); int dm_target_init(void);
struct target_type *dm_get_target(const char *name); struct target_type *dm_get_target(const char *name);
/* dm.c */ /* dm.c */
struct mapped_device *dm_find_by_name(const char *name); struct mapped_device *dm_find_by_name(const char *name);
struct mapped_device *dm_find_by_minor(int minor); struct mapped_device *dm_find_by_minor(int minor);
int dm_create(const char *name, int minor); int dm_create(const char *name, int minor);
int dm_remove(const char *name); int dm_remove(const char *name);
int dm_bind(struct mapped_device *md, struct dm_table *t);
int dm_activate(struct mapped_device *md); int dm_activate(struct mapped_device *md);
void dm_suspend(struct mapped_device *md); void dm_suspend(struct mapped_device *md);
/* dm-table.c */ /* dm-table.c */
int dm_table_start(struct mapped_device *md); struct dm_table *dm_table_create(void);
int dm_table_add_entry(struct mapped_device *md, offset_t high, void dm_table_destroy(struct dm_table *t);
dm_map_fn target, void *context);
int dm_table_complete(struct mapped_device *md); int dm_table_add_entry(struct dm_table *t, offset_t high,
void dm_table_free(struct mapped_device *md); dm_map_fn target, void *private);
int dm_table_complete(struct dm_table *t);
/* dm-fs.c */ /* dm-fs.c */
int dm_fs_init(void); int dm_fs_init(void);