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

o Rejig activation code device dependencies to make things a bit more robust

and further reduce the number of ioctl calls made.
o Metadata area struct change.
o Make config file accessible to activation functions & get stripe_filler
  from it.
o Allow kernel to return snapshot status as a fraction or a percentage.
This commit is contained in:
Alasdair Kergon 2003-04-24 22:09:13 +00:00
parent 75833edb80
commit a9953411a8
4 changed files with 237 additions and 92 deletions

View File

@ -144,7 +144,7 @@ int lv_info(const struct logical_volume *lv, struct lvinfo *info)
if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name))) {
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
@ -174,7 +174,7 @@ int lv_snapshot_percent(struct logical_volume *lv, float *percent)
if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name))) {
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
@ -217,7 +217,7 @@ static int _lv_activate(struct logical_volume *lv)
int r;
struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name))) {
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
@ -234,7 +234,7 @@ static int _lv_deactivate(struct logical_volume *lv)
int r;
struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name))) {
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}
@ -251,7 +251,7 @@ static int _lv_suspend(struct logical_volume *lv)
int r;
struct dev_manager *dm;
if (!(dm = dev_manager_create(lv->vg->name))) {
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cf))) {
stack;
return 0;
}

View File

@ -28,6 +28,11 @@ int activation(void);
int driver_version(char *version, size_t size);
int library_version(char *version, size_t size);
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s);
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s);
int lv_activate(struct cmd_context *cmd, const char *lvid_s);
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s);
/*
* Returns 1 if info structure has been populated, else 0.
*/
@ -37,20 +42,6 @@ int lv_info(const struct logical_volume *lv, struct lvinfo *info);
*/
int lv_snapshot_percent(struct logical_volume *lv, float *percent);
/*
* These should eventually use config file
* to determine whether or not to activate
*/
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s);
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s);
int lv_activate(struct cmd_context *cmd, const char *lvid_s);
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s);
/*
* FIXME:
* I don't like the *lvs_in_vg* function names.
*/
/*
* Return number of LVs in the VG that are active.
*/

View File

@ -10,6 +10,7 @@
#include "hash.h"
#include "lvm-string.h"
#include "fs.h"
#include "defaults.h"
#include <libdevmapper.h>
#include <limits.h>
@ -45,7 +46,8 @@ enum {
RELOAD = 1,
VISIBLE = 2,
READWRITE = 3,
SUSPENDED = 4
SUSPENDED = 4,
NOPROPAGATE = 5
};
typedef enum {
@ -73,8 +75,8 @@ struct dev_layer {
struct logical_volume *lv;
/*
* Devices that must be created before this one can be
* created. Holds str_lists.
* Devices that must be created before this one can be created.
* Reloads get propagated to this list. Holds str_lists.
*/
struct list pre_create;
@ -85,9 +87,14 @@ struct dl_list {
struct dev_layer *dl;
};
static const char *stripe_filler = NULL;
struct dev_manager {
struct pool *mem;
struct config_tree *cf;
const char *stripe_filler;
char *vg_name;
/*
@ -375,6 +382,11 @@ static int _status_run(const char *name, const char *uuid,
return r;
}
static int _status(const char *name, const char *uuid,
unsigned long long *start, unsigned long long *length,
char **type, uint32_t type_size, char **params,
uint32_t param_size) __attribute__ ((unused));
static int _status(const char *name, const char *uuid,
unsigned long long *start, unsigned long long *length,
char **type, uint32_t type_size, char **params,
@ -392,6 +404,78 @@ static int _status(const char *name, const char *uuid,
return 0;
}
static int _percent_run(const char *name, const char *uuid,
const char *target_type, float *percent)
{
int r = 0;
struct dm_task *dmt;
void *next = NULL;
uint64_t start, length;
char *type = NULL;
char *params = NULL;
float percent2;
uint64_t numerator, denominator;
uint64_t total_numerator = 0, total_denominator = 0;
*percent = -1;
if (!(dmt = _setup_task(name, uuid, DM_DEVICE_STATUS))) {
stack;
return 0;
}
if (!dm_task_run(dmt)) {
stack;
goto out;
}
do {
next = dm_get_next_target(dmt, next, &start, &length, &type,
&params);
if (!type || !params || strcmp(type, target_type))
continue;
if (strcmp(type, "snapshot"))
continue;
/* Snapshot */
if (index(params, '/')) {
if (sscanf(params, "%" PRIu64 "/%" PRIu64,
&numerator, &denominator) == 2) {
total_numerator += numerator;
total_denominator += denominator;
}
continue;
} else if (sscanf(params, "%f", &percent2) == 1) {
*percent += percent2;
*percent /= 2;
}
} while (next);
if (total_denominator)
*percent = (float) total_numerator *100 / total_denominator;
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
static int _percent(const char *name, const char *uuid, const char *target_type,
float *percent)
{
if (uuid && *uuid && _percent_run(NULL, uuid, target_type, percent))
return 1;
if (name && _percent_run(name, NULL, target_type, percent))
return 1;
return 0;
}
static int _rename(struct dev_layer *dl, char *newname)
{
int r = 1;
@ -553,7 +637,7 @@ static int _suspend_or_resume(const char *name, action_t suspend)
static int _suspend(struct dev_layer *dl)
{
if (dl->info.suspended)
if (!dl->info.exists || dl->info.suspended)
return 1;
if (!_suspend_or_resume(dl->name, SUSPEND)) {
@ -567,7 +651,7 @@ static int _suspend(struct dev_layer *dl)
static int _resume(struct dev_layer *dl)
{
if (!dl->info.suspended)
if (!dl->info.exists || !dl->info.suspended)
return 1;
if (!_suspend_or_resume(dl->name, RESUME)) {
@ -588,47 +672,73 @@ static int _resume(struct dev_layer *dl)
* Emit a target for a given segment.
* FIXME: tidy this function.
*/
static int _emit_target(struct dm_task *dmt, struct lv_segment *seg)
static int _emit_target(struct dev_manager *dm, struct dm_task *dmt,
struct lv_segment *seg)
{
char params[1024];
uint64_t esize = seg->lv->vg->extent_size;
uint32_t s, stripes = seg->stripes;
uint32_t s, areas = seg->area_count;
int w = 0, tw = 0;
const char *filler = "/dev/ioerror";
const char *target = NULL;
const char *trailing_space;
if (stripes == 1) {
if (!seg->area[0].pv) {
target = "error";
goto add_target;
} else
switch (seg->type) {
case SEG_SNAPSHOT:
log_error("_emit_target: Internal error: Can't handle "
"SEG_SNAPSHOT");
return 0;
/* Target formats:
* linear [device offset]+
* striped #stripes stripe_size [device offset]+
*/
case SEG_STRIPED:
if (areas == 1)
target = "linear";
} else if (stripes > 1) {
target = "striped";
if ((tw = lvm_snprintf(params, sizeof(params), "%u %u ",
stripes, seg->stripe_size)) < 0)
goto error;
w = tw;
else if (areas > 1) {
target = "striped";
if ((tw = lvm_snprintf(params, sizeof(params), "%u %u ",
areas, seg->stripe_size)) < 0)
goto error;
w = tw;
} else {
log_error("_emit_target: Internal error: SEG_STRIPED "
"with no stripes");
return 0;
}
break;
case SEG_MIRRORED:
break;
}
for (s = 0; s < stripes; s++, w += tw) {
if (!seg->area[s].pv || !seg->area[s].pv->dev)
for (s = 0; s < areas; s++, w += tw) {
trailing_space = (areas - s - 1) ? " " : "";
if ((seg->area[s].type == AREA_PV &&
(!seg->area[s].u.pv.pv || !seg->area[s].u.pv.pv->dev)) ||
(seg->area[s].type == AREA_LV && !seg->area[s].u.lv.lv))
tw = lvm_snprintf(params + w, sizeof(params) - w,
"%s 0%s", filler,
s == (stripes - 1) ? "" : " ");
else
"%s 0%s", dm->stripe_filler,
trailing_space);
else if (seg->area[s].type == AREA_PV)
tw = lvm_snprintf(params + w, sizeof(params) - w,
"%s %" PRIu64 "%s",
dev_name(seg->area[s].pv->dev),
(seg->area[s].pv->pe_start +
(esize * seg->area[s].pe)),
s == (stripes - 1) ? "" : " ");
dev_name(seg->area[s].u.pv.pv->dev),
(seg->area[s].u.pv.pv->pe_start +
(esize * seg->area[s].u.pv.pe)),
trailing_space);
else
tw = lvm_snprintf(params + w, sizeof(params) - w,
"%s/%s %" PRIu64 "%s", dm_dir(),
_build_name(dm->mem,
seg->lv->vg->name,
seg->area[s].u.lv.lv->
name, NULL),
esize * seg->area[s].u.lv.le,
trailing_space);
if (tw < 0)
goto error;
}
add_target:
log_debug("Adding target: %" PRIu64 " %" PRIu64 " %s %s",
esize * seg->le, esize * seg->len, target, params);
@ -641,7 +751,7 @@ static int _emit_target(struct dm_task *dmt, struct lv_segment *seg)
return 1;
error:
log_error("Insufficient space to write target parameters.");
log_error("Insufficient space in params[] to write target parameters.");
return 0;
}
@ -654,7 +764,7 @@ static int _populate_vanilla(struct dev_manager *dm,
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
if (!_emit_target(dmt, seg)) {
if (!_emit_target(dm, dmt, seg)) {
log_error("Unable to build table for '%s'", lv->name);
return 0;
}
@ -734,7 +844,8 @@ static int _populate_snapshot(struct dev_manager *dm,
/*
* dev_manager implementation.
*/
struct dev_manager *dev_manager_create(const char *vg_name)
struct dev_manager *dev_manager_create(const char *vg_name,
struct config_tree *cf)
{
struct pool *mem;
struct dev_manager *dm;
@ -750,6 +861,13 @@ struct dev_manager *dev_manager_create(const char *vg_name)
}
dm->mem = mem;
dm->cf = cf;
if (!stripe_filler) {
stripe_filler = find_config_str(cf->root,
"activation/missing_stripe_filler",
'/', DEFAULT_STRIPE_FILLER);
}
dm->stripe_filler = stripe_filler;
if (!(dm->vg_name = pool_strdup(dm->mem, vg_name))) {
stack;
@ -807,23 +925,7 @@ int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
int dev_manager_snapshot_percent(struct dev_manager *dm,
struct logical_volume *lv, float *percent)
{
char *name, *type, *params;
unsigned long long start, length;
unsigned int numerator, denominator;
/* FIXME: Use #defines - & move allocations into _status_run ? */
uint32_t type_size = 32;
uint32_t param_size = 32;
if (!(type = pool_alloc(dm->mem, sizeof(*type) * type_size))) {
stack;
return 0;
}
if (!(params = pool_alloc(dm->mem, sizeof(*params) * param_size))) {
stack;
return 0;
}
char *name;
/*
* Build a name for the top layer.
@ -836,31 +938,16 @@ int dev_manager_snapshot_percent(struct dev_manager *dm,
/*
* Try and get some info on this device.
*/
log_debug("Getting device status for %s", name);
if (!(_status(name, lv->lvid.s, &start, &length, &type, type_size,
&params, param_size))) {
log_debug("Getting device status percentage for %s", name);
if (!(_percent(name, lv->lvid.s, "snapshot", percent))) {
stack;
return 0;
}
/* FIXME Ensure this is a *snapshot* target with percentage! */
/* FIXME pool_free ? */
/* If the snapshot isn't available, percent will be -1 */
*percent = -1;
if (!params)
return 0;
if (index(params, '/')) {
if (sscanf(params, "%u/%u", &numerator, &denominator) == 2) {
*percent = (float) numerator *100 / denominator;
return 1;
}
} else if (sscanf(params, "%f", percent) == 1)
return 1;
return 0;
return 1;
}
static struct dev_layer *_create_dev(struct dev_manager *dm, char *name,
@ -958,13 +1045,36 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv)
* only one layer.
*/
struct dev_layer *dl;
struct list *segh;
struct lv_segment *seg;
uint32_t s;
if (!(dl = _create_layer(dm, NULL, lv))) {
stack;
return 0;
}
dl->populate = _populate_vanilla;
_set_flag(dl, VISIBLE);
if (lv->status & VISIBLE_LV)
_set_flag(dl, VISIBLE);
/* Add dependencies for any LVs that segments refer to */
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
if (seg->type != SEG_STRIPED && seg->type != SEG_MIRRORED)
continue;
for (s = 0; s < seg->area_count; s++) {
if (seg->area[s].type != AREA_LV)
continue;
if (!_pre_list_add(dm->mem, &dl->pre_create,
_build_dlid(dm->mem,
seg->area[s].u.lv.lv->
lvid.s, NULL))) {
stack;
return 0;
}
_set_flag(dl, NOPROPAGATE);
}
}
return 1;
}
@ -1117,6 +1227,10 @@ static int _trace_layer_marks(struct dev_manager *dm, struct dev_layer *dl,
if (_get_flag(dep, flag))
continue;
/* Only propagate LV ACTIVE dependencies for now */
if ((flag != ACTIVE) && _get_flag(dl, NOPROPAGATE))
continue;
_set_flag(dep, flag);
if (!_trace_layer_marks(dm, dep, flag)) {
@ -1452,6 +1566,7 @@ static int _add_existing_layer(struct dev_manager *dm, const char *name)
return 1;
}
/* FIXME Get this info directly from the driver not the unreliable fs */
static int _scan_existing_devices(struct dev_manager *dm)
{
const char *dev_dir = dm_dir();
@ -1570,12 +1685,34 @@ static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv)
return _add_lvs(dm->mem, &dm->reload_list, old_origin);
}
static int _remove_suspended_lvs(struct dev_manager *dm,
struct logical_volume *lv)
{
struct logical_volume *suspended;
struct snapshot *s;
struct list *sh, *suspend_head;
suspend_head = &dm->suspend_list;
/* Remove from list any snapshots with given origin */
list_iterate(sh, suspend_head) {
suspended = list_item(sh, struct lv_list)->lv;
if ((s = find_cow(suspended)) && s->origin == lv) {
_remove_lv(suspend_head, suspended);
}
}
_remove_lv(suspend_head, lv);
return 1;
}
static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
{
int found;
char *dlid;
struct list *lvh;
struct logical_volume *lv;
struct dev_layer *dl;
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
@ -1585,16 +1722,24 @@ static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
return 0;
}
found = hash_lookup(dm->layers, dlid) ? 1 : 0;
dl = hash_lookup(dm->layers, dlid);
pool_free(dm->mem, dlid);
if (found) {
log_debug("Found active lv %s", lv->name);
if (dl) {
log_debug("Found active lv %s%s", lv->name,
dl->info.suspended ? " (suspended)" : "");
if (!_add_lv(dm->mem, &dm->active_list, lv)) {
stack;
return 0;
}
if (dl->info.suspended) {
if (!_add_lv(dm->mem, &dm->suspend_list, lv)) {
stack;
return 0;
}
}
}
}
@ -1630,6 +1775,13 @@ static int _action(struct dev_manager *dm, struct logical_volume *lv,
}
}
if (action == SUSPEND || action == RESUME || action == ACTIVATE)
/* Get into known state - remove from suspend list if present */
if (!_remove_suspended_lvs(dm, lv)) {
stack;
return 0;
}
if (action == SUSPEND) {
if (!_add_lvs(dm->mem, &dm->suspend_list, lv)) {
stack;

View File

@ -8,6 +8,7 @@
#define _LVM_DEV_MANAGER_H
#include "metadata.h"
#include "config.h"
struct dev_manager;
struct dm_info;
@ -15,7 +16,8 @@ struct dm_info;
/*
* Constructor and destructor.
*/
struct dev_manager *dev_manager_create(const char *vg_name);
struct dev_manager *dev_manager_create(const char *vg_name,
struct config_tree *cf);
void dev_manager_destroy(struct dev_manager *dm);
/*