1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

o This should complete the dev_manager alg. Please could people now

report any activation oddities they see.
This commit is contained in:
Joe Thornber 2002-03-11 20:36:04 +00:00
parent 41967a0276
commit 2ec94d4daf
2 changed files with 223 additions and 133 deletions

View File

@ -54,7 +54,7 @@
*/
enum {
MARK = 0,
ACTIVE = 0,
DIRTY = 1,
VISIBLE = 2
};
@ -85,11 +85,30 @@ struct dev_layer {
struct list pre_active;
};
struct dl_list {
struct list list;
struct dev_layer *dl;
};
struct dev_manager {
struct pool *mem;
char *vg_name;
/*
* list of struct lv_list, contains lvs that we wish to
* be active after execution.
*/
struct list active_list;
/*
* Layers that need reloading.
*/
struct list dirty_list;
/*
* Layers that will need removing after activation.
*/
struct list remove_list;
struct hash_table *layers;
@ -115,8 +134,8 @@ static inline void _clear_flag(struct dev_layer *dl, int bit) {
/*
* Device layer names are all of the form <vg>-<lv>-<layer>, any
* other hyphens that appear in these names are quoted with yet
* another hyphen. The top layer of any device is always called
* 'top'. eg, vg0-lvol0.
* another hyphen. The top layer of any device has no layer
* name. eg, vg0-lvol0.
*/
static void _count_hyphens(const char *str, size_t *len, int *hyphens)
{
@ -227,6 +246,7 @@ static int _load(struct dev_manager *dm, struct dev_layer *dl, int task)
if (_get_flag(dl, VISIBLE))
fs_add_lv(dl->lv, dl->name);
dl->info.exists = 1;
return r;
}
@ -526,6 +546,7 @@ struct dev_manager *dev_manager_create(const char *vg_name)
}
list_init(&dm->active_list);
list_init(&dm->dirty_list);
list_init(&dm->remove_list);
return dm;
@ -803,23 +824,23 @@ static int _expand_lv(struct dev_manager *dm, struct logical_volume *lv)
/*
* Clears the mark bit on all layers.
*/
static void _clear_marks(struct dev_manager *dm)
static void _clear_marks(struct dev_manager *dm, int flag)
{
struct hash_node *hn;
struct dev_layer *dl;
hash_iterate (hn, dm->layers) {
dl = hash_get_data(dm->layers, hn);
_clear_flag(dl, MARK);
_clear_flag(dl, flag);
}
}
/*
* Starting with a given layer this function recurses through all
* dependent layers setting the mark bit.
* Propogates marks via the pre_create dependency list.
*/
static int _mark_pre_create(struct dev_manager *dm, struct dev_layer *dl)
static int _trace_layer_marks(struct dev_manager *dm, struct dev_layer *dl,
int flag)
{
struct list *sh;
char *name;
@ -833,12 +854,12 @@ static int _mark_pre_create(struct dev_manager *dm, struct dev_layer *dl)
return 0;
}
if (_get_flag(dep, MARK))
if (_get_flag(dep, flag))
continue;
_set_flag(dep, MARK);
_set_flag(dep, flag);
if (!_mark_pre_create(dm, dep)) {
if (!_trace_layer_marks(dm, dep, flag)) {
stack;
return 0;
}
@ -847,9 +868,52 @@ static int _mark_pre_create(struct dev_manager *dm, struct dev_layer *dl)
return 1;
}
void _emit(struct dev_layer *dl)
/*
* Calls _trace_single for every marked layer.
*/
static int _trace_all_marks(struct dev_manager *dm, int flag)
{
log_print("emitting layer '%s'", dl->name);
struct hash_node *hn;
struct dev_layer *dl;
hash_iterate (hn, dm->layers) {
dl = hash_get_data(dm->layers, hn);
if (_get_flag(dl, flag) && !_trace_layer_marks(dm, dl, flag)) {
stack;
return 0;
}
}
return 1;
}
/*
* Marks the top layers, then traces these through the
* dependencies.
*/
static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag)
{
struct list *lvh;
struct logical_volume *lv;
struct dev_layer *dl;
list_iterate (lvh, lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (!(dl = _lookup(dm, lv->name, NULL))) {
stack;
return 0;
}
_set_flag(dl, flag);
}
if (!_trace_all_marks(dm, flag)) {
stack;
return 0;
}
return 1;
}
/*
@ -904,104 +968,15 @@ int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
return 1;
}
/*
* Layers are removed in a top-down manner.
*/
int _remove_rec(struct dev_manager *dm, struct dev_layer *dl)
static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg)
{
struct list *sh;
struct dev_layer *dep;
char *name;
if (dl->info.exists && dl->info.suspended && !_resume(dl)) {
stack;
return 0;
}
if (!_remove(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 (!_remove_rec(dm, dep)) {
stack;
return 0;
}
}
return 1;
}
static int _mark_dependants(struct dev_manager *dm)
{
struct hash_node *hn;
struct dev_layer *dl;
_clear_marks(dm);
/*
* Mark any dependants.
*/
hash_iterate (hn, dm->layers) {
dl = hash_get_data(dm->layers, hn);
if (!_get_flag(dl, MARK)) {
if (!_mark_pre_create(dm, dl)) {
stack;
return 0;
}
if (_get_flag(dl, MARK)) {
log_err("Circular device dependency found for "
"'%s'.",
dl->name);
return 0;
}
}
}
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, *next;
struct dev_layer *dl;
for (hn = hash_get_first(dm->layers); hn; hn = next) {
next = hash_get_next(dm->layers, hn);
dl = hash_get_data(dm->layers, hn);
if (!_get_flag(dl, MARK))
hash_remove(dm->layers, dl->name);
}
return 1;
}
static int _select_lv(struct dev_manager *dm, struct logical_volume *lv)
{
struct dev_layer *dl;
struct list *lvh;
struct logical_volume *lvt;
/*
* Build layers for complete vg.
*/
list_iterate (lvh, &lv->vg->lvs) {
list_iterate (lvh, &vg->lvs) {
lvt = list_item(lvh, struct lv_list)->lv;
if (!_expand_lv(dm, lvt)) {
stack;
@ -1009,21 +984,78 @@ static int _select_lv(struct dev_manager *dm, struct logical_volume *lv)
}
}
return 1;
}
static int _fill_in_remove_list(struct dev_manager *dm)
{
struct hash_node *hn;
struct dev_layer *dl;
struct dl_list *dll;
hash_iterate (hn, dm->layers) {
dl = hash_get_data(dm->layers, hn);
if (!_get_flag(dl, ACTIVE)) {
dll = pool_alloc(dm->mem, sizeof(*dll));
if (!dll) {
stack;
return 0;
}
dll->dl = dl;
list_add(&dm->remove_list, &dll->list);
}
}
return 1;
}
/*
* Layers are removed in a top-down manner.
*/
int _remove_old_layers(struct dev_manager *dm)
{
int change;
/*
* Mark the desired logical volume.
* FIXME: quick hack. We just loop round removing
* unopened devices, until we run out of things to close.
*/
if (!(dl = _lookup(dm, lv->name, NULL))) {
log_err("Couldn't find top layer of '%s'.", lv->name);
do {
struct list *rh, *n;
struct dev_layer *dl;
change = 0;
for (rh = dm->remove_list.n; rh != &dm->remove_list; rh = n) {
n = rh->n;
dl = list_item(rh, struct dl_list)->dl;
if (!_info(dl->name, &dl->info)) {
stack;
return 0;
}
if (dl->info.exists && !dl->info.open_count) {
change = 1;
if (!_remove(dl)) {
stack;
return 0;
}
list_del(rh);
}
}
} while(change);
if (!list_empty(&dm->remove_list)) {
log_err("Couldn't remove all redundant layers.");
return 0;
}
_set_flag(dl, MARK);
if (!_mark_pre_create(dm, dl)) {
stack;
return 0;
}
_prune_unmarked(dm);
return 1;
}
@ -1032,22 +1064,35 @@ static int _select_lv(struct dev_manager *dm, struct logical_volume *lv)
* layers in the manager, and tries to issue the correct
* instructions to activate them in order.
*/
static int _execute(struct dev_manager *dm, struct logical_volume *lv,
int (*cmd)(struct dev_manager *dm, struct dev_layer *dl))
static int _execute(struct dev_manager *dm, struct volume_group *vg)
{
struct hash_node *hn;
struct dev_layer *dl;
if (!_select_lv(dm, lv)) {
if (!_build_all_layers(dm, vg)) {
stack;
return 0;
}
/*
* We need to make a list of top level devices, ie. those
* that have no entries in 'pre_create'.
* Mark all dirty layers.
*/
if (!_mark_dependants(dm)) {
_clear_marks(dm, DIRTY);
if (!_mark_lvs(dm, &dm->dirty_list, DIRTY)) {
stack;
return 0;
}
/*
* Mark all active layers.
*/
_clear_marks(dm, ACTIVE);
if (!_mark_lvs(dm, &dm->active_list, ACTIVE)) {
stack;
return 0;
}
if (!_fill_in_remove_list(dm)) {
stack;
return 0;
}
@ -1058,8 +1103,13 @@ static int _execute(struct dev_manager *dm, struct logical_volume *lv,
hash_iterate (hn, dm->layers) {
dl = hash_get_data(dm->layers, hn);
if (!_get_flag(dl, MARK))
cmd(dm, dl);
if (_get_flag(dl, ACTIVE) && _get_flag(dl, VISIBLE))
_create_rec(dm, dl);
}
if (!_remove_old_layers(dm)) {
stack;
return 0;
}
return 1;
@ -1161,21 +1211,36 @@ static int _scan_existing_devices(struct dev_manager *dm)
return r;
}
static int _add_active(struct dev_manager *dm, struct logical_volume *lv)
static int _add_lv(struct pool *mem,
struct list *head, struct logical_volume *lv)
{
struct lv_list *lvl;
if (!(lvl = pool_alloc(dm->mem, sizeof(*lvl)))) {
if (!(lvl = pool_alloc(mem, sizeof(*lvl)))) {
stack;
return 0;
}
lvl->lv = lv;
list_add(&dm->active_list, &lvl->list);
list_add(head, &lvl->list);
return 1;
}
static void _remove_lv(struct list *head, struct logical_volume *lv)
{
struct list *lvh;
struct lv_list *lvl;
list_iterate (lvh, head) {
lvl = list_item(lvh, struct lv_list);
if (lvl->lv == lv) {
list_del(lvh);
break;
}
}
}
static int _fill_in_active_list(struct dev_manager *dm,
struct volume_group *vg)
{
@ -1187,7 +1252,7 @@ static int _fill_in_active_list(struct dev_manager *dm,
list_iterate (lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
name = _build_name(dm->mem, dm->vg_name, lv->name, "");
name = _build_name(dm->mem, dm->vg_name, lv->name, NULL);
if (!name) {
stack;
return 0;
@ -1196,15 +1261,23 @@ static int _fill_in_active_list(struct dev_manager *dm,
found = hash_lookup(dm->layers, name) ? 1 : 0;
pool_free(dm->mem, name);
if (found && !_add_active(dm, lv)) {
stack;
return 0;
if (found) {
log_verbose("Active lv '%s' found.", lv->name);
if (!_add_lv(dm->mem, &dm->active_list, lv)) {
stack;
return 0;
}
}
}
return 1;
}
/*
* FIXME: There's a lot of common code between activate and
* deactivate.
*/
int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv)
{
if (!_scan_existing_devices(dm)) {
@ -1217,12 +1290,17 @@ int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv)
return 0;
}
if (!_add_active(dm, lv)) {
/*
* Remove it so we don't add it twice.
*/
_remove_lv(&dm->active_list, lv);
if (!_add_lv(dm->mem, &dm->dirty_list, lv) ||
!_add_lv(dm->mem, &dm->active_list, lv)) {
stack;
return 0;
}
if (!_execute(dm, lv, _create_rec)) {
if (!_execute(dm, lv->vg)) {
stack;
return 0;
}
@ -1232,7 +1310,19 @@ int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv)
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv)
{
if (!_execute(dm, lv, _remove_rec)) {
if (!_scan_existing_devices(dm)) {
stack;
return 0;
}
if (!_fill_in_active_list(dm, lv->vg)) {
stack;
return 0;
}
_remove_lv(&dm->active_list, lv);
if (!_execute(dm, lv->vg)) {
stack;
return 0;
}

View File

@ -22,7 +22,7 @@ struct id {
*/
union lvid {
struct id id[2];
char s[2 * sizeof(struct id) + 1];
char s[2 * sizeof(struct id) + 1];
};
int lvid_from_lvnum(union lvid *lvid, struct id *vgid, int lv_num);