mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
o proc interface is getting there.
This commit is contained in:
parent
a2f6acada0
commit
d534900b91
@ -39,107 +39,115 @@
|
||||
*/
|
||||
|
||||
const char *_fs_dir = "device-mapper";
|
||||
const char *_control_name = "control";
|
||||
|
||||
static struct proc_dir_entry *_proc_dir;
|
||||
static struct proc_dir_entry *_control;
|
||||
|
||||
static devfs_handle_t _dev_dir;
|
||||
static devfs_handle_t _dev_control;
|
||||
|
||||
static int _line_splitter(struct file *file, const char *buffer,
|
||||
unsigned long *count, void *data)
|
||||
|
||||
typedef int (process_fn)(const char *b, const char *e);
|
||||
|
||||
struct pf_data {
|
||||
process_fn data;
|
||||
int minor;
|
||||
};
|
||||
|
||||
int dm_init_fs()
|
||||
{
|
||||
/* create /dev/device-manager */
|
||||
struct pf_data *pfd = kmalloc(sizeof(*pfd), GFP_KERNEL);
|
||||
|
||||
if (!pfd)
|
||||
return 0;
|
||||
|
||||
_dev_dir = devfs_mk_dir(0, _fs_dir, NULL);
|
||||
|
||||
/* and put the control device in it */
|
||||
_dev_control = devfs_register(0 , "device-mapper", 0, DM_CHAR_MAJOR, 0,
|
||||
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
|
||||
&dm_ctl_fops, NULL);
|
||||
if (!(_proc_dir = create_proc_entry(_fs_dir, S_IFDIR, &proc_root)))
|
||||
goto fail;
|
||||
|
||||
if (!(_proc_dir = create_proc_entry(_fs_dir, S_IFDIR, &proc_root))) {
|
||||
devfs_unregister(_dm_control);
|
||||
_dm_control = 0;
|
||||
return 0;
|
||||
}
|
||||
if (!(_control = create_proc_entry(_control_name, 0, _proc_dir)))
|
||||
goto fail;
|
||||
|
||||
_control->write_proc = _line_splitter;
|
||||
|
||||
pfd->fn = _process_control;
|
||||
pfd->minor = -1;
|
||||
_control->data = pfd;
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
dm_fin_fs();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dm_fin_fs(void)
|
||||
{
|
||||
/* FIXME: unregister all devices and proc interfaces */
|
||||
if (_control) {
|
||||
remove_proc_entry(_control_name, _proc_dir);
|
||||
_control = 0;
|
||||
}
|
||||
|
||||
devfs_unregister(_dev_control);
|
||||
devfs_unregister(_dev_dir);
|
||||
if (_proc_dir) {
|
||||
remove_proc_entry(_fs_dir, &proc_root);
|
||||
_proc_dir = 0;
|
||||
}
|
||||
|
||||
remove_proc_entry(_fs_dir, &proc_root);
|
||||
if (_dev_dir)
|
||||
devfs_unregister(_dev_dir);
|
||||
}
|
||||
|
||||
int dm_add(const char *name)
|
||||
int _process_control(const char *b, const char *e, int minor)
|
||||
{
|
||||
const char *wb, *we;
|
||||
char *name[64];
|
||||
long minor = -1;
|
||||
int create = 0;
|
||||
|
||||
}
|
||||
/*
|
||||
* create <name> [minor]
|
||||
* remove <name>
|
||||
*/
|
||||
if (!_get_word(b, e, &wb, &we))
|
||||
return -EINVAL;
|
||||
b = we;
|
||||
|
||||
int dm_remove(const char *name)
|
||||
{
|
||||
if (!_tok_cmp("create", wb, we))
|
||||
create = 1;
|
||||
|
||||
}
|
||||
else if (_tok_cmp("remove", wb, we))
|
||||
return -EINVAL;
|
||||
|
||||
if (!_get_word(b, e, &wb, &we))
|
||||
return -EINVAL;
|
||||
b = we;
|
||||
|
||||
static int _setup_targets(struct mapped_device *md, struct device_table *t)
|
||||
{
|
||||
int i;
|
||||
offset_t low = 0;
|
||||
_tok_cpy(name, sizeof(buffer), wb, we);
|
||||
|
||||
md->num_targets = t->count;
|
||||
md->targets = __aligned(sizeof(*md->targets) * md->num_targets,
|
||||
NODE_SIZE);
|
||||
if (create) {
|
||||
if (_get_word(b, e, &wb, &we)) {
|
||||
minor = simple_strtol(wb, &we, 10);
|
||||
|
||||
for (i = 0; i < md->num_targets; i++) {
|
||||
struct mapper *m = _find_mapper(t->map[i].type);
|
||||
if (!m)
|
||||
return 0;
|
||||
|
||||
if (!m->ctr(low, t->map[i].high + 1,
|
||||
t->map[i].context, md->contexts + i)) {
|
||||
WARN("contructor for '%s' failed", m->name);
|
||||
return 0;
|
||||
if (we == wb)
|
||||
return -EINVAL;
|
||||
}
|
||||
_create_dm(name, minor);
|
||||
|
||||
md->targets[i] = m->map;
|
||||
} else {
|
||||
if (!_get_word(b, e, &wb, &we))
|
||||
return -EINVAL;
|
||||
|
||||
_tok_cpy(name, sizeof(buffer), wb, we);
|
||||
_remove_dm(name, minor);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const char *_eat_white(const char *b, const char *e)
|
||||
{
|
||||
while(b != e && isspace((int) *b))
|
||||
b++;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static int _get_line(const char *b, const char *e,
|
||||
const char **lb, const char **le)
|
||||
{
|
||||
b = _eat_white(b, e);
|
||||
if (b == e)
|
||||
return 0;
|
||||
|
||||
lb = b;
|
||||
while((b != e) && *b != '\n')
|
||||
b++;
|
||||
|
||||
if (b == e) {
|
||||
/* FIXME: handle partial lines */
|
||||
return 0;
|
||||
}
|
||||
|
||||
*le = b;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _process_line(const char *b, const char *e)
|
||||
static int _process_table(const char *b, const char *e, int minor)
|
||||
{
|
||||
struct target *t;
|
||||
const char *wb, *we;
|
||||
@ -161,47 +169,131 @@ static int _process_line(const char *b, const char *e)
|
||||
/* FIXME: add module loading here */
|
||||
return -EPARAM;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static int _write_proc(struct file *file, const char *buffer,
|
||||
unsigned long *count, void *data)
|
||||
static int _process_table(const char *b, const char *e, int minor)
|
||||
{
|
||||
const char *b, *e, *lb, *le;
|
||||
int minor = (int) data;
|
||||
const char *wb, *we;
|
||||
struct mapped_device *md = dm_get_dev(minor);
|
||||
|
||||
if (!md)
|
||||
return -ENXIO;
|
||||
|
||||
b = buffer;
|
||||
e = buffer + e;
|
||||
if (!_get_word(b, e, &wb, &we))
|
||||
return -EINVAL;
|
||||
|
||||
if (!is_loading(md)) {
|
||||
if (!_get_line(b, e, &lb, &le))
|
||||
return -EPARAM;
|
||||
if (!_tok_cmp("begin", b, e)) {
|
||||
/* suspend the device if it's active */
|
||||
dm_suspend(md);
|
||||
|
||||
if (tokcmp("begin\n", lb, le))
|
||||
return -EPARAM;
|
||||
/* start loading a table */
|
||||
dm_start_table(md);
|
||||
|
||||
start_loading(md);
|
||||
b = le;
|
||||
} else if (!_tok_cmp("end", b, e)) {
|
||||
/* activate the device ... <evil chuckle> ... */
|
||||
dm_complete_table(md);
|
||||
dm_activate(md);
|
||||
|
||||
} else {
|
||||
/* add the new entry */
|
||||
int len = we - wb;
|
||||
char high_s[64], *ptr;
|
||||
char target[64];
|
||||
struct target *t;
|
||||
offset_t high;
|
||||
|
||||
if (len > sizeof(high_s))
|
||||
return 0;
|
||||
|
||||
strncpy(high_s, wb, we - wb);
|
||||
high_s[len] = '\0';
|
||||
|
||||
high = strtol(high_s, &ptr, 10);
|
||||
if (ptr == high_s)
|
||||
return 0;
|
||||
|
||||
b = we;
|
||||
if (!_get_word(b, e, &wb, &we))
|
||||
return 0;
|
||||
|
||||
len = we - wb;
|
||||
if (len > sizeof(target))
|
||||
return 0;
|
||||
|
||||
strncpy(target, wb, len);
|
||||
target[len] = '\0';
|
||||
|
||||
if (!(t = dm_get_target(target)))
|
||||
return 0;
|
||||
|
||||
dm_add_entry(md, high, t, context);
|
||||
}
|
||||
|
||||
while(_get_line(b, e, &lb, &le)) {
|
||||
if (!tokcmp("end\n", wb, we)) {
|
||||
/* FIXME: finish */
|
||||
}
|
||||
|
||||
ret = _process_line(lb, le);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
b = le;
|
||||
}
|
||||
|
||||
fail:
|
||||
/* stop the table load */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *_eat_space(const char *b, const char *e)
|
||||
{
|
||||
while(b != e && isspace((int) *b))
|
||||
b++;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static int _get_word(const char *b, const char *e,
|
||||
const char **wb, const char *we)
|
||||
{
|
||||
b = _eat_space(b, e);
|
||||
|
||||
if (b == e)
|
||||
return 0;
|
||||
|
||||
*wb = b;
|
||||
while(b != e && !isspace((int) b))
|
||||
b++;
|
||||
*we = e;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _line_splitter(struct file *file, const char *buffer,
|
||||
unsigned long *count, void *data)
|
||||
{
|
||||
const char *b = buffer, *e = buffer + count, *lb;
|
||||
struct pf_data *pfd = (struct pf_data *) data;
|
||||
|
||||
while(b < e) {
|
||||
b = _eat_space(b, e);
|
||||
if (b == e)
|
||||
return 0;
|
||||
|
||||
lb = b;
|
||||
while((b != e) && *b != '\n')
|
||||
b++;
|
||||
|
||||
if (!pfd->fn(lb, b, pfd->minor))
|
||||
return lb - buffer;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int _tok_cmp(const char *str, const char *b, const char *e)
|
||||
{
|
||||
while (*str && b != e) {
|
||||
if (*str < *b)
|
||||
return -1;
|
||||
|
||||
if (*str > *b)
|
||||
return 1;
|
||||
|
||||
str++, b++;
|
||||
}
|
||||
|
||||
if (!*str && b == e)
|
||||
return 0;
|
||||
|
||||
if (*str)
|
||||
return 1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -107,6 +107,45 @@ void dm_free_btree(struct mapped_device *md)
|
||||
__free_aligned(md->contexts);
|
||||
}
|
||||
|
||||
static int _setup_targets(struct mapped_device *md, struct device_table *t)
|
||||
{
|
||||
int i;
|
||||
offset_t low = 0;
|
||||
|
||||
md->num_targets = t->count;
|
||||
md->targets = __aligned(sizeof(*md->targets) * md->num_targets,
|
||||
NODE_SIZE);
|
||||
|
||||
for (i = 0; i < md->num_targets; i++) {
|
||||
struct mapper *m = _find_mapper(t->map[i].type);
|
||||
if (!m)
|
||||
return 0;
|
||||
|
||||
if (!m->ctr(low, t->map[i].high + 1,
|
||||
t->map[i].context, md->contexts + i)) {
|
||||
WARN("contructor for '%s' failed", m->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
md->targets[i] = m->map;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_start_table(struct mapped_device *md)
|
||||
{
|
||||
/* if this is active, suspend it */
|
||||
}
|
||||
|
||||
int dm_add_entry(struct mapped_device *md, offset_t high,
|
||||
dm_map_fn target, void *context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int dm_activate_table(struct mapped_device *md)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@
|
||||
const char *_name = "device-mapper";
|
||||
int _version[3] = {1, 0, 0};
|
||||
|
||||
spinlock_t _dev_lock;
|
||||
struct rw_semaphore _dev_lock;
|
||||
static int _dev_count = 0;
|
||||
static struct mapped_device *_devs[MAX_DEVICES];
|
||||
|
||||
@ -171,9 +171,9 @@ static int _request_fn(request_queue_t *q, int rw, struct buffer_head *bh);
|
||||
*/
|
||||
static int _init(void)
|
||||
{
|
||||
_init_mds();
|
||||
init_rwsem(&_dev_lock);
|
||||
|
||||
if (!_register_std_targets())
|
||||
if (!dm_std_targets())
|
||||
return -EIO; /* FIXME: better error value */
|
||||
|
||||
/* set up the arrays */
|
||||
@ -219,50 +219,6 @@ static void _fin(void)
|
||||
_version[0], _version[1], _version[2]);
|
||||
}
|
||||
|
||||
/*
|
||||
* character device fns
|
||||
*/
|
||||
static int _ctl_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
|
||||
MOD_INC_USE_COUNT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ctl_close(struct inode *inode, struct file *file)
|
||||
{
|
||||
MOD_DEC_USE_COUNT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ctl_ioctl(struct inode *inode, struct file *file,
|
||||
uint command, ulong a)
|
||||
{
|
||||
struct dm_request req;
|
||||
|
||||
if (copy_from_user(&req, (void *) a, sizeof(req)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (command) {
|
||||
case MAPPED_DEVICE_CREATE:
|
||||
return _create_dev(req.minor, req.name);
|
||||
break;
|
||||
|
||||
case MAPPED_DEVICE_DESTROY:
|
||||
return _destroy_dev(req.minor);
|
||||
break;
|
||||
|
||||
default:
|
||||
WARN("_ctl_ioctl: unknown command 0x%x", command);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* block device functions
|
||||
*/
|
||||
@ -370,10 +326,14 @@ static int _request_fn(request_queue_t *q, int rw, struct buffer_head *bh)
|
||||
if (minor >= MAX_DEVICES)
|
||||
return -ENXIO;
|
||||
|
||||
down_read(&_dev_lock);
|
||||
md = _devs[minor];
|
||||
if (MINOR(md->dev != minor))
|
||||
up_read(&_dev_lock);
|
||||
|
||||
if (!md)
|
||||
return -ENXIO;
|
||||
|
||||
down_read(&md->lock);
|
||||
for (l = 0; l < md->depth; l++) {
|
||||
next_node = ((KEYS_PER_NODE + 1) * next_node) + i;
|
||||
node = md->index[l] + (next_node * KEYS_PER_NODE);
|
||||
@ -393,6 +353,8 @@ static int _request_fn(request_queue_t *q, int rw, struct buffer_head *bh)
|
||||
} else
|
||||
buffer_IO_error(bh);
|
||||
|
||||
|
||||
up_read(&md->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -426,12 +388,12 @@ static struct mapped_device *_alloc_dev(int minor)
|
||||
int i;
|
||||
struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);
|
||||
|
||||
spin_lock(&_dev_lock);
|
||||
down_write(&_dev_lock);
|
||||
minor = (minor < 0) ? __any_old_dev() : __specific_dev(minor);
|
||||
|
||||
if (minor < 0) {
|
||||
WARN("no free devices available");
|
||||
spin_unlock(&_dev_lock);
|
||||
up_write(&_dev_lock);
|
||||
kfree(md);
|
||||
return 0;
|
||||
}
|
||||
@ -441,7 +403,7 @@ static struct mapped_device *_alloc_dev(int minor)
|
||||
clear_bit(md->status, DM_CREATED);
|
||||
|
||||
_devs[minor] = md;
|
||||
spin_unlock(&_dev_lock);
|
||||
up_write(&_dev_lock);
|
||||
|
||||
return *d;
|
||||
}
|
||||
@ -450,60 +412,75 @@ static void _free_dev(struct mapped_device *md)
|
||||
{
|
||||
int i, minor = MINOR(md->dev);
|
||||
|
||||
spin_lock(&_dev_lock);
|
||||
down_write(&_dev_lock);
|
||||
_devs[i] = 0;
|
||||
spin_unlock(&_dev_lock);
|
||||
up_write(&_dev_lock);
|
||||
|
||||
kfree(md);
|
||||
}
|
||||
|
||||
static struct mapped_device *__find_dev(const char *name)
|
||||
static inline struct mapped_device *__find_dev(const char *name)
|
||||
{
|
||||
int i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mapped_device *dm_find_name(const char *name)
|
||||
{
|
||||
int i;
|
||||
struct mapped_device *md;
|
||||
|
||||
down_read(&_dev_lock);
|
||||
for (i = 0; i < MAX_DEVICES; i++)
|
||||
if (_devs[i] && !strcmp(_devs[i]->name, name))
|
||||
return _devs[i];
|
||||
|
||||
return 0;
|
||||
up_read(&_dev_lock);
|
||||
}
|
||||
|
||||
static int _create_dev(int minor, const char *name)
|
||||
struct mapped_device *dm_find_minor(int minor)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int dm_create(int minor, const char *name)
|
||||
{
|
||||
struct mapped_device *md = _alloc_dev(minor);
|
||||
|
||||
if (!md)
|
||||
return -ENXIO;
|
||||
|
||||
spin_lock(&_dev_lock);
|
||||
down_write(&_dev_lock);
|
||||
if (__find_dev(name)) {
|
||||
WARN("device with that name already exists");
|
||||
spin_unlock(&_dev_lock);
|
||||
up_write(&_dev_lock);
|
||||
_free_dev(md);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
strcpy(md->name, name);
|
||||
spin_unlock(&_dev_lock);
|
||||
|
||||
dm_fs_add_lv(md);
|
||||
up_write(&_dev_lock);
|
||||
}
|
||||
|
||||
static int _destroy_dev(int minor)
|
||||
static int dm_remove(const char *name, int minor)
|
||||
{
|
||||
struct mapped_device *md;
|
||||
int minor;
|
||||
|
||||
spin_lock(&_dev_lock);
|
||||
md = _devs[minor];
|
||||
down_write(&_dev_lock);
|
||||
if (!(md = __find_dev(name))) {
|
||||
up_write(&_dev_lock);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
minor = MINOR(md->dev);
|
||||
clear_bit(md->status, CREATED);
|
||||
spin_unlock(&_dev_lock);
|
||||
|
||||
dm_clear_table(md);
|
||||
|
||||
spin_lock(&_dev_lock);
|
||||
_free_dev(md);
|
||||
spin_unlock(&_dev_lock);
|
||||
|
||||
dm_fs_remove_lv(md);
|
||||
_devs[minor] = 0;
|
||||
up_write(&_dev_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -36,11 +36,12 @@
|
||||
|
||||
enum {
|
||||
DM_LOADING,
|
||||
DM_CREATED,
|
||||
DM_ACTIVE,
|
||||
};
|
||||
|
||||
struct mapped_device {
|
||||
struct rw_semaphore lock;
|
||||
|
||||
kdev_t dev;
|
||||
char name[DM_NAME_LEN];
|
||||
|
||||
@ -59,8 +60,6 @@ struct mapped_device {
|
||||
|
||||
/* used by dm-fs.c */
|
||||
devfs_handle_t devfs_entry;
|
||||
char incomplete_input[64];
|
||||
|
||||
};
|
||||
|
||||
/* dm-target.c */
|
||||
@ -76,11 +75,20 @@ struct target {
|
||||
struct target *dm_get_target(const char *name);
|
||||
int dm_std_targets(void);
|
||||
|
||||
/* dm.c */
|
||||
|
||||
/* dm.c */
|
||||
struct mapped_device *dm_find_name(const char *name);
|
||||
struct mapped_device *dm_find_minor(int minor);
|
||||
|
||||
void dm_suspend(struct mapped_device *md);
|
||||
void dm_activate(struct mapped_device *md);
|
||||
|
||||
/* dm-table.c */
|
||||
int dm_build_btree(struct mapped_device *md);
|
||||
int dm_start_table(struct mapped_device *md);
|
||||
int dm_add_entry(struct mapped_device *md, offset_t high,
|
||||
dm_map_fn target, void *context);
|
||||
int dm_complete_table(struct mapped_device *md);
|
||||
|
||||
|
||||
/* dm-fs.c */
|
||||
int dm_init_fs(void);
|
||||
|
Loading…
Reference in New Issue
Block a user