mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
o Sync with cvs, dev_manager still needs to be wired into activate.c
This commit is contained in:
parent
7b9e789f9c
commit
ca73e23fd0
492
lib/activate/dev_manager.c
Normal file
492
lib/activate/dev_manager.c
Normal file
@ -0,0 +1,492 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "dev_manager.h"
|
||||
#include "pool.h"
|
||||
#include "hash.h"
|
||||
#include "log.h"
|
||||
|
||||
|
||||
/* layer types */
|
||||
enum {
|
||||
VANILLA,
|
||||
ORIGIN,
|
||||
SNAPSHOT
|
||||
};
|
||||
|
||||
struct dev_layer {
|
||||
char *name;
|
||||
int mark;
|
||||
|
||||
/*
|
||||
* Setup the dm_task.
|
||||
*/
|
||||
int type;
|
||||
int exists;
|
||||
int suspended;
|
||||
struct logical_volume *lv;
|
||||
|
||||
/*
|
||||
* Devices that must be created before this one can be
|
||||
* created. Holds str_lists.
|
||||
*/
|
||||
struct list pre_create;
|
||||
|
||||
/*
|
||||
* Devices that must be created before this one can be
|
||||
* unsuspended. Holds str_lists.
|
||||
*/
|
||||
struct list pre_active;
|
||||
};
|
||||
|
||||
struct dl_list {
|
||||
struct list list;
|
||||
struct dev_layer *layer;
|
||||
};
|
||||
|
||||
|
||||
struct dev_manager {
|
||||
struct pool *mem;
|
||||
|
||||
char *vg_name;
|
||||
struct hash_table *layers;
|
||||
};
|
||||
|
||||
static void _count_colons(const char *str, size_t *len, int *colons)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
for (ptr = str; *ptr; ptr++, (*len)++)
|
||||
if (*ptr == ':')
|
||||
(*colons)++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies a string, quoting colons with colons.
|
||||
*/
|
||||
static void _quote_colons(char **out, const char *src)
|
||||
{
|
||||
while (*src) {
|
||||
if (*src == ':')
|
||||
*(*out)++ = ':';
|
||||
|
||||
*(*out)++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
static char *_build_name(struct pool *mem, const char *vg,
|
||||
const char *lv, const char *layer)
|
||||
{
|
||||
size_t len = 0;
|
||||
int colons = 0;
|
||||
char *r, *out;
|
||||
|
||||
_count_colons(vg, &len, &colons);
|
||||
_count_colons(lv, &len, &colons);
|
||||
_count_colons(layer, &len, &colons);
|
||||
|
||||
len += colons + 1;
|
||||
|
||||
if (!(r = pool_alloc(mem, len))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out = r;
|
||||
_quote_colons(&out, vg);
|
||||
_quote_colons(&out, lv);
|
||||
_quote_colons(&out, layer);
|
||||
*out = '\0';
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* dev_manager implementation.
|
||||
*/
|
||||
struct dev_manager *dev_manager_create(const char *vg_name)
|
||||
{
|
||||
struct pool *mem;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!(mem = pool_create(16 * 1024))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(dm = pool_alloc(mem, sizeof(*dm)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
dm->mem = mem;
|
||||
|
||||
if (!(dm->vg_name = pool_strdup(dm->mem, vg_name))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(dm->layers = hash_create(32))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
return dm;
|
||||
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dev_manager_destroy(struct dev_manager *dm)
|
||||
{
|
||||
hash_destroy(dm->layers);
|
||||
pool_destroy(dm->mem);
|
||||
}
|
||||
|
||||
static struct dev_layer *
|
||||
_create_layer(struct pool *mem, const char *layer,
|
||||
int type, struct logical_volume *lv)
|
||||
{
|
||||
struct dev_layer *dl;
|
||||
|
||||
if (!(dl = pool_zalloc(mem, sizeof(*dl)))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(dl->name = _build_name(mem, lv->vg->name, lv->name, layer))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dl->type = type;
|
||||
dl->suspended = 0;
|
||||
dl->lv = lv;
|
||||
|
||||
return dl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds the specified layer.
|
||||
*/
|
||||
static struct dev_layer *_lookup(struct dev_manager *dm, const char *lv, const char *layer)
|
||||
{
|
||||
char *name;
|
||||
struct dev_layer *dl;
|
||||
|
||||
if (!(name = _build_name(dm->mem, dm->vg_name, lv, layer))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dl = hash_lookup(dm->layers, name);
|
||||
pool_free(dm->mem, name);
|
||||
return dl;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Inserts the dev_layers for a logical volume.
|
||||
*/
|
||||
static int _expand_lv(struct dev_manager *dm, struct logical_volume *lv)
|
||||
{
|
||||
struct snapshot *s;
|
||||
|
||||
/*
|
||||
* FIXME: this doesn't cope with recursive snapshots yet.
|
||||
*/
|
||||
if ((s = find_cow(lv))) {
|
||||
/*
|
||||
* snapshot(org, cow)
|
||||
* cow
|
||||
*/
|
||||
log_err("Snapshot devices not supported yet.");
|
||||
return 0;
|
||||
|
||||
|
||||
} else if (lv_is_origin(lv)) {
|
||||
/*
|
||||
* origin(org)
|
||||
* org
|
||||
*/
|
||||
log_err("Origin devices not supported yet.");
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
/*
|
||||
* only one layer.
|
||||
*/
|
||||
struct dev_layer *dl;
|
||||
if (!(dl = _create_layer(dm->mem, "top", VANILLA, lv))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!hash_insert(dm->layers, dl->name, dl)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int _get_info(const char *name, struct dm_info *info)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
|
||||
log_very_verbose("Getting device info for %s", name);
|
||||
if (!(dmt = setup_dm_task(name, DM_DEVICE_INFO))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dm_task_get_info(dmt, info)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Clears the mark bit on all layers.
|
||||
*/
|
||||
static void _clear_marks(struct dev_manager *dm)
|
||||
{
|
||||
struct hash_node *hn;
|
||||
struct dev_layer *dl;
|
||||
|
||||
hash_iterate (hn, dm->layers) {
|
||||
dl = hash_get_data(dm->layers, hn);
|
||||
dl->mark = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Starting with a given layer this function recurses through all
|
||||
* dependent layers setting the mark bit.
|
||||
*/
|
||||
static int _mark_pre_create(struct dev_manager *dm, struct dev_layer *dl)
|
||||
{
|
||||
struct list *sh;
|
||||
char *name;
|
||||
struct dev_layer *dep;
|
||||
|
||||
list_iterate (sh, &dl->pre_create) {
|
||||
name = list_item(sh, struct str_list)->str;
|
||||
|
||||
if (!(dep = hash_lookup(dm->layers, name))) {
|
||||
log_err("Couldn't find device layer '%s'.", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dep->mark)
|
||||
continue;
|
||||
|
||||
dep->mark = 1;
|
||||
|
||||
if (!_mark_pre_create(dm, dep)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void _emit(struct dev_layer *dl)
|
||||
{
|
||||
log_print("emitting layer '%s'", dl->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Recurses through the tree, ensuring that devices are created
|
||||
* in correct order.
|
||||
*/
|
||||
int _create(struct dev_layer *dl)
|
||||
{
|
||||
struct list *sh;
|
||||
struct dev_layer *dep;
|
||||
char *name;
|
||||
|
||||
if (dl->exists && !_suspend(dl)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate (sh, &dl->pre_create) {
|
||||
name = list_item(sh, struct str_list)->str;
|
||||
|
||||
if (!(dep = hash_lookup(dm_layers, name))) {
|
||||
log_err("Couldn't find device layer '%s'.", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_create(dep)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (dl->exists) {
|
||||
/* reload */
|
||||
if (!_reload(dl)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_resume(dl)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* create */
|
||||
if (!_create(dl)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The guts of the activation unit, this examines the device
|
||||
* layers in the manager, and tries to issue the correct activate
|
||||
* them in the correct order.
|
||||
*/
|
||||
static int _execute(struct dev_manager *dm)
|
||||
{
|
||||
struct hash_node *hn;
|
||||
struct dev_layer *dl;
|
||||
|
||||
/*
|
||||
* We need to make a list of top level devices, ie. those
|
||||
* that have no entries in 'pre_create'.
|
||||
*/
|
||||
_clear_marks(dm);
|
||||
|
||||
/*
|
||||
* Mark any dependents.
|
||||
*/
|
||||
hash_iterate (hn, dm->layers) {
|
||||
dl = hash_get_data(dm->layers, hn);
|
||||
|
||||
if (!dl->mark) {
|
||||
if (!_mark_pre_create(dm, dl)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dl->mark) {
|
||||
log_err("Circular device dependency found for '%s'.",
|
||||
dl->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now only top level devices will be unmarked.
|
||||
*/
|
||||
hash_iterate (hn, dm->layers) {
|
||||
dl = hash_get_data(dm->layers, hn);
|
||||
|
||||
if (!dl->mark)
|
||||
_emit(dl);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove all layers from the hash table that do not have their
|
||||
* mark flag set.
|
||||
*/
|
||||
static int _prune_unmarked(struct dev_manager *dm)
|
||||
{
|
||||
struct hash_node *hn;
|
||||
struct dev_layer *dl;
|
||||
|
||||
for (hn = hash_get_first(dm->layers); hn;
|
||||
hn = hash_get_next(dm->layers, hn)) {
|
||||
dl = hash_get_data(dm->layers, hn);
|
||||
|
||||
if (!dl->mark)
|
||||
hash_remove(dm->layers, dl->name);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv)
|
||||
{
|
||||
struct dev_layer *dl;
|
||||
struct list *lvh;
|
||||
|
||||
/*
|
||||
* Build layers for complete vg.
|
||||
*/
|
||||
list_iterate (lvh, &lv->vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (!_expand_lv(dm, lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the desired logical volume.
|
||||
*/
|
||||
dl = _lookup(dm, lv->name, "top");
|
||||
dl->mark = 1;
|
||||
if (!_mark_pre_create(dm, dl)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_prune_unmarked(dm);
|
||||
|
||||
/*
|
||||
* Now we are just left with the layers required to
|
||||
* implement the lv.
|
||||
*/
|
||||
|
||||
if (!_execute(dm)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dev_manager_reactivate(struct dev_manager *dm, struct logical_volume *lv)
|
||||
{
|
||||
log_err("dev_manager_reactivate not implemented.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv)
|
||||
{
|
||||
log_err("dev_manager_reactivate not implemented.");
|
||||
return 0;
|
||||
}
|
||||
|
36
lib/activate/dev_manager.h
Normal file
36
lib/activate/dev_manager.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef _LVM_DEV_MANAGER_H
|
||||
#define _LVM_DEV_MANAGER_H
|
||||
|
||||
#include "metadata.h"
|
||||
|
||||
struct dev_manager;
|
||||
|
||||
/*
|
||||
* Constructor and destructor.
|
||||
*/
|
||||
struct dev_manager *dev_manager_create(const char *vg_name);
|
||||
void dev_manager_destroy(struct dev_manager *dm);
|
||||
|
||||
/*
|
||||
* The device handler is responsible for creating all the layered
|
||||
* dm devices, and ensuring that all constraints are maintained
|
||||
* (eg, an origin is created before its snapshot, but is not
|
||||
* unsuspended until the snapshot is also created.)
|
||||
*/
|
||||
int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv);
|
||||
int dev_manager_reactivate(struct dev_manager *dm, struct logical_volume *lv);
|
||||
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);
|
||||
|
||||
|
||||
/*
|
||||
* Put the desired changes into effect.
|
||||
*/
|
||||
int dev_manager_execute(struct dev_manager *dm);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user