mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-22 17:35:59 +03:00
14ce9d49f1
Things to note: o Changes to the dm-*.c files have been kept as small as possible during the development of the new fs interface and there are a few places where the new code does odd things to give the original code what it wants. These places will gradually go away during the next few days once we are sure the new code is sound. o I've spent most of my testing time looking at the parser since thats where a lot of the changes are, I've not checked the actual I/O very much, but then that code hasn't changed at all. o The print operation in the target type operations is there to help in debugging and will go away eventually o There are some other printk's which will also go away once we are sure that things are working correctly. o I've tagged the old code with PRE_DMFS if you want to use that until this is stable. o There are no kernel patches for this yet (will fix after lunch... :-) o Makefile needs some changes o need to EXPORT_SYMBOL(deny_write_access); in ksyms.c How to use the new interface ? mount -t dmfs dmfs /mnt/dm cd /mnt/dm mkdir fish fish/tank cd fish/tank cat ~/my.table > table cd .. ln -s tank ACTIVE Creates a logical volume called fish and activates a table called tank, if there is a problem doing the link, look in /mnt/dm/fish/tank/errors to see what is wrong. If you see any odd things happening, let me know right away as I'm sure there'll be one or two things that slipped through my testing.
181 lines
3.0 KiB
C
181 lines
3.0 KiB
C
/*
|
|
* dm-target.c
|
|
*
|
|
* Copyright (C) 2001 Sistina Software (UK) Limited
|
|
*
|
|
* This file is released under the GPL.
|
|
*/
|
|
|
|
/*
|
|
* 16/08/2001 - First Version [Joe Thornber]
|
|
*/
|
|
|
|
#include "dm.h"
|
|
#include <linux/kmod.h>
|
|
|
|
struct tt_internal {
|
|
struct target_type tt;
|
|
|
|
struct list_head list;
|
|
long use;
|
|
};
|
|
|
|
static LIST_HEAD(_targets);
|
|
static rwlock_t _lock = RW_LOCK_UNLOCKED;
|
|
|
|
#define DM_MOD_NAME_SIZE 32
|
|
|
|
static inline struct tt_internal *__find_target_type(const char *name)
|
|
{
|
|
struct list_head *tmp;
|
|
struct tt_internal *ti;
|
|
|
|
for(tmp = _targets.next; tmp != &_targets; tmp = tmp->next) {
|
|
|
|
ti = list_entry(tmp, struct tt_internal, list);
|
|
if (!strcmp(name, ti->tt.name))
|
|
return ti;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct tt_internal *get_target_type(const char *name)
|
|
{
|
|
struct tt_internal *ti;
|
|
|
|
read_lock(&_lock);
|
|
ti = __find_target_type(name);
|
|
|
|
if (ti) {
|
|
if (ti->use == 0 && ti->tt.module)
|
|
__MOD_INC_USE_COUNT(ti->tt.module);
|
|
ti->use++;
|
|
}
|
|
read_unlock(&_lock);
|
|
|
|
return ti;
|
|
}
|
|
|
|
static void load_module(const char *name)
|
|
{
|
|
char module_name[DM_MOD_NAME_SIZE] = "dm-";
|
|
|
|
/* Length check for strcat() below */
|
|
if (strlen(name) > (DM_MOD_NAME_SIZE - 4))
|
|
return;
|
|
|
|
strcat(module_name, name);
|
|
request_module(module_name);
|
|
}
|
|
|
|
struct target_type *dm_get_target_type(const char *name)
|
|
{
|
|
struct tt_internal *ti = get_target_type(name);
|
|
|
|
if (!ti) {
|
|
load_module(name);
|
|
ti = get_target_type(name);
|
|
}
|
|
|
|
return ti ? &ti->tt : 0;
|
|
}
|
|
|
|
void dm_put_target_type(struct target_type *t)
|
|
{
|
|
struct tt_internal *ti = (struct tt_internal *) t;
|
|
|
|
read_lock(&_lock);
|
|
if (--ti->use == 0 && ti->tt.module)
|
|
__MOD_DEC_USE_COUNT(ti->tt.module);
|
|
|
|
if (ti->use < 0)
|
|
BUG();
|
|
read_unlock(&_lock);
|
|
}
|
|
|
|
static struct tt_internal *alloc_target(struct target_type *t)
|
|
{
|
|
struct tt_internal *ti = kmalloc(sizeof(*ti), GFP_KERNEL);
|
|
|
|
if (ti) {
|
|
memset(ti, 0, sizeof(*ti));
|
|
ti->tt = *t;
|
|
}
|
|
|
|
return ti;
|
|
}
|
|
|
|
int dm_register_target(struct target_type *t)
|
|
{
|
|
int rv = 0;
|
|
struct tt_internal *ti = alloc_target(t);
|
|
|
|
if (!ti)
|
|
return -ENOMEM;
|
|
|
|
write_lock(&_lock);
|
|
if (__find_target_type(t->name))
|
|
rv = -EEXIST;
|
|
else
|
|
list_add(&ti->list, &_targets);
|
|
|
|
write_unlock(&_lock);
|
|
return rv;
|
|
}
|
|
|
|
int dm_unregister_target(struct target_type *t)
|
|
{
|
|
struct tt_internal *ti = (struct tt_internal *) t;
|
|
int rv = -ETXTBSY;
|
|
|
|
write_lock(&_lock);
|
|
if (ti->use == 0) {
|
|
list_del(&ti->list);
|
|
kfree(ti);
|
|
rv = 0;
|
|
}
|
|
write_unlock(&_lock);
|
|
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* io-err: always fails an io, useful for bringing
|
|
* up LV's that have holes in them.
|
|
*/
|
|
static int io_err_ctr(struct dm_table *t, offset_t b, offset_t l,
|
|
char *args, void **context)
|
|
{
|
|
*context = 0;
|
|
return 0;
|
|
}
|
|
|
|
static void io_err_dtr(struct dm_table *t, void *c)
|
|
{
|
|
/* empty */
|
|
}
|
|
|
|
static int io_err_map(struct buffer_head *bh, int rw, void *context)
|
|
{
|
|
buffer_IO_error(bh);
|
|
return 0;
|
|
}
|
|
|
|
static struct target_type error_target = {
|
|
name: "error",
|
|
ctr: io_err_ctr,
|
|
dtr: io_err_dtr,
|
|
map: io_err_map
|
|
};
|
|
|
|
|
|
int dm_target_init(void)
|
|
{
|
|
return dm_register_target(&error_target);
|
|
}
|
|
|
|
EXPORT_SYMBOL(dm_register_target);
|
|
EXPORT_SYMBOL(dm_unregister_target);
|
|
|