mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-10 05:18:36 +03:00
tagging
This commit is contained in:
parent
6dbf31c0c3
commit
b89c4e9002
@ -36,6 +36,7 @@ SOURCES=\
|
||||
format_text/format-text.c \
|
||||
format_text/import.c \
|
||||
format_text/import_vsn1.c \
|
||||
format_text/tags.c \
|
||||
format_text/text_label.c \
|
||||
label/label.c \
|
||||
locking/file_locking.c \
|
||||
|
@ -139,6 +139,7 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
||||
list_init(&vg->pvs);
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
list_init(&vg->tags);
|
||||
|
||||
if (!_check_vgs(pvs, &partial))
|
||||
goto bad;
|
||||
|
@ -56,9 +56,9 @@ int import_pv(struct pool *mem, struct device *dev,
|
||||
|
||||
if (vg &&
|
||||
strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id)))
|
||||
log_very_verbose("System ID %s on %s differs from %s for "
|
||||
"volume group", pvd->system_id,
|
||||
dev_name(pv->dev), vg->system_id);
|
||||
log_very_verbose("System ID %s on %s differs from %s for "
|
||||
"volume group", pvd->system_id,
|
||||
dev_name(pv->dev), vg->system_id);
|
||||
|
||||
/*
|
||||
* If exported, we still need to flag in pv->status too because
|
||||
@ -76,6 +76,8 @@ int import_pv(struct pool *mem, struct device *dev,
|
||||
pv->pe_count = pvd->pe_total;
|
||||
pv->pe_alloc_count = pvd->pe_allocated;
|
||||
|
||||
list_init(&pv->tags);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -162,7 +164,7 @@ int export_pv(struct pool *mem, struct volume_group *vg,
|
||||
if (vg &&
|
||||
(!*vg->system_id ||
|
||||
strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id))))
|
||||
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
|
||||
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
|
||||
|
||||
//pvd->pv_major = MAJOR(pv->dev);
|
||||
|
||||
@ -314,6 +316,7 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
|
||||
lv->le_count = lvd->lv_allocated_le;
|
||||
|
||||
list_init(&lv->segments);
|
||||
list_init(&lv->tags);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ static int _print_header(struct formatter *f,
|
||||
|
||||
static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
char buffer[256];
|
||||
char buffer[4096];
|
||||
|
||||
if (!id_write_format(&vg->id, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
@ -280,14 +280,24 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
_outf(f, "id = \"%s\"", buffer);
|
||||
|
||||
_outf(f, "seqno = %u", vg->seqno);
|
||||
|
||||
if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_outf(f, "status = %s", buffer);
|
||||
|
||||
if (!list_empty(&vg->tags)) {
|
||||
if (!print_tags(&vg->tags, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
_outf(f, "tags = %s", buffer);
|
||||
}
|
||||
|
||||
if (vg->system_id && *vg->system_id)
|
||||
_outf(f, "system_id = \"%s\"", vg->system_id);
|
||||
|
||||
if (!_out_size(f, (uint64_t) vg->extent_size, "extent_size = %u",
|
||||
vg->extent_size)) {
|
||||
stack;
|
||||
@ -314,7 +324,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct physical_volume *pv;
|
||||
char buffer[256];
|
||||
char buffer[4096];
|
||||
const char *name;
|
||||
|
||||
_outf(f, "physical_volumes {");
|
||||
@ -348,8 +358,16 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_outf(f, "status = %s", buffer);
|
||||
|
||||
if (!list_empty(&pv->tags)) {
|
||||
if (!print_tags(&pv->tags, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
_outf(f, "tags = %s", buffer);
|
||||
}
|
||||
|
||||
_outf(f, "pe_start = %" PRIu64, pv->pe_start);
|
||||
if (!_out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
|
||||
"pe_count = %u", pv->pe_count)) {
|
||||
@ -372,6 +390,7 @@ static int _print_segment(struct formatter *f, struct volume_group *vg,
|
||||
unsigned int s;
|
||||
const char *name;
|
||||
const char *type;
|
||||
char buffer[4096];
|
||||
|
||||
_outf(f, "segment%u {", count);
|
||||
_inc_indent(f);
|
||||
@ -386,6 +405,14 @@ static int _print_segment(struct formatter *f, struct volume_group *vg,
|
||||
f->nl(f);
|
||||
_outf(f, "type = \"%s\"", get_segtype_string(seg->type));
|
||||
|
||||
if (!list_empty(&seg->tags)) {
|
||||
if (!print_tags(&seg->tags, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
_outf(f, "tags = %s", buffer);
|
||||
}
|
||||
|
||||
switch (seg->type) {
|
||||
case SEG_SNAPSHOT:
|
||||
_outf(f, "chunk_size = %u", seg->chunk_size);
|
||||
@ -490,6 +517,9 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap,
|
||||
seg.cow = snap->cow;
|
||||
seg.chunk_size = snap->chunk_size;
|
||||
|
||||
/* Can't tag a snapshot independently of its origin */
|
||||
list_init(&seg.tags);
|
||||
|
||||
if (!_print_segment(f, snap->origin->vg, 1, &seg)) {
|
||||
stack;
|
||||
return 0;
|
||||
@ -524,7 +554,7 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_segment *seg;
|
||||
char buffer[256];
|
||||
char buffer[4096];
|
||||
int seg_count;
|
||||
|
||||
/*
|
||||
@ -555,8 +585,16 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_outf(f, "status = %s", buffer);
|
||||
|
||||
if (!list_empty(&lv->tags)) {
|
||||
if (!print_tags(&lv->tags, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
_outf(f, "tags = %s", buffer);
|
||||
}
|
||||
|
||||
if (lv->alloc != ALLOC_DEFAULT)
|
||||
_outf(f, "allocation_policy = \"%s\"",
|
||||
get_alloc_string(lv->alloc));
|
||||
|
@ -1640,7 +1640,7 @@ struct format_type *create_text_format(struct cmd_context *cmd)
|
||||
fmt->ops = &_text_handler;
|
||||
fmt->name = FMT_TEXT_NAME;
|
||||
fmt->alias = FMT_TEXT_ALIAS;
|
||||
fmt->features = FMT_SEGMENTS | FMT_MDAS;
|
||||
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS;
|
||||
|
||||
if (!(mda_lists = dbg_malloc(sizeof(struct mda_lists)))) {
|
||||
log_error("Failed to allocate dir_list");
|
||||
|
@ -46,6 +46,9 @@ struct text_vg_version_ops *text_vg_vsn1_init(void);
|
||||
int print_flags(uint32_t status, int type, char *buffer, size_t size);
|
||||
int read_flags(uint32_t *status, int type, struct config_value *cv);
|
||||
|
||||
int print_tags(struct list *tags, char *buffer, size_t size);
|
||||
int read_tags(struct pool *mem, struct list *tags, struct config_value *cv);
|
||||
|
||||
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
|
||||
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||
uint32_t size);
|
||||
|
@ -178,6 +178,16 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_init(&pv->tags);
|
||||
|
||||
/* Optional tags */
|
||||
if ((cn = find_config_node(pvn, "tags", '/')) &&
|
||||
!(read_tags(mem, &pv->tags, cn->v))) {
|
||||
log_error("Couldn't read tags for physical volume %s in %s.",
|
||||
dev_name(pv->dev), vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* adjust the volume group. */
|
||||
vg->extent_count += pv->pe_count;
|
||||
vg->free_count += pv->pe_count;
|
||||
@ -293,6 +303,14 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
|
||||
seg->status = seg_status;
|
||||
seg->extents_moved = extents_moved;
|
||||
|
||||
/* Optional tags */
|
||||
if ((cn = find_config_node(sn, "tags", '/')) &&
|
||||
!(read_tags(mem, &seg->tags, cn->v))) {
|
||||
log_error("Couldn't read tags for a segment of %s/%s.",
|
||||
vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (segtype) {
|
||||
case SEG_SNAPSHOT:
|
||||
lv->status |= SNAPSHOT;
|
||||
@ -544,6 +562,15 @@ static int _read_lvnames(struct format_instance *fid, struct pool *mem,
|
||||
lv->read_ahead = 0;
|
||||
|
||||
list_init(&lv->segments);
|
||||
list_init(&lv->tags);
|
||||
|
||||
/* Optional tags */
|
||||
if ((cn = find_config_node(lvn, "tags", '/')) &&
|
||||
!(read_tags(mem, &lv->tags, cn->v))) {
|
||||
log_error("Couldn't read tags for logical volume %s/%s.",
|
||||
vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->vg = vg;
|
||||
vg->lv_count++;
|
||||
@ -748,6 +775,14 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
list_init(&vg->tags);
|
||||
|
||||
/* Optional tags */
|
||||
if ((cn = find_config_node(vgn, "tags", '/')) &&
|
||||
!(read_tags(mem, &vg->tags, cn->v))) {
|
||||
log_error("Couldn't read tags for volume group %s.", vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_sections(fid, "logical_volumes", _read_lvnames, mem, vg,
|
||||
vgn, pv_hash, 1)) {
|
||||
|
67
lib/format_text/tags.c
Normal file
67
lib/format_text/tags.c
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "import-export.h"
|
||||
#include "pool.h"
|
||||
#include "str_list.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
int print_tags(struct list *tags, char *buffer, size_t size)
|
||||
{
|
||||
struct str_list *sl;
|
||||
int first = 1;
|
||||
|
||||
if (!emit_to_buffer(&buffer, &size, "[")) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate_items(sl, tags) {
|
||||
if (!first) {
|
||||
if (!emit_to_buffer(&buffer, &size, ", ")) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
first = 0;
|
||||
|
||||
if (!emit_to_buffer(&buffer, &size, "\"%s\"", sl->str)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!emit_to_buffer(&buffer, &size, "]")) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int read_tags(struct pool *mem, struct list *tags, struct config_value *cv)
|
||||
{
|
||||
if (cv->type == CFG_EMPTY_ARRAY)
|
||||
return 1;
|
||||
|
||||
while (cv) {
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_error("Found a tag that is not a string");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!str_list_add(mem, tags, pool_strdup(mem, cv->v.str))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cv = cv->next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
@ -60,6 +60,8 @@ struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t stripes)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(&seg->tags);
|
||||
|
||||
return seg;
|
||||
}
|
||||
|
||||
@ -519,6 +521,7 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
lv->size = UINT64_C(0);
|
||||
lv->le_count = 0;
|
||||
list_init(&lv->segments);
|
||||
list_init(&lv->tags);
|
||||
|
||||
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
|
||||
stack;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "metadata.h"
|
||||
#include "toolcontext.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "str_list.h"
|
||||
|
||||
/*
|
||||
* Test whether two segments could be merged by the current merging code
|
||||
@ -40,6 +41,9 @@ static int _segments_compatible(struct lv_segment *first,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!str_list_lists_equal(&first->tags, &second->tags))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -129,6 +133,11 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||
len = sizeof(*seg) + (seg->area_count * sizeof(seg->area[0]));
|
||||
memcpy(split_seg, seg, len);
|
||||
|
||||
if (!str_list_dup(lv->vg->cmd->mem, &split_seg->tags, &seg->tags)) {
|
||||
log_error("LV segment tags duplication failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In case of a striped segment, the offset has to be / stripes */
|
||||
if (seg->type == SEG_STRIPED)
|
||||
offset /= seg->area_count;
|
||||
|
@ -211,6 +211,8 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
vg->snapshot_count = 0;
|
||||
list_init(&vg->snapshots);
|
||||
|
||||
list_init(&vg->tags);
|
||||
|
||||
if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg_name,
|
||||
NULL))) {
|
||||
log_error("Failed to create format instance");
|
||||
@ -293,6 +295,8 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
pv->pe_alloc_count = 0;
|
||||
pv->fmt = fmt;
|
||||
|
||||
list_init(&pv->tags);
|
||||
|
||||
if (!fmt->ops->pv_setup(fmt, pe_start, existing_extent_count,
|
||||
existing_extent_size,
|
||||
pvmetadatacopies, pvmetadatasize, mdas,
|
||||
@ -562,6 +566,7 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
list_init(&vg->pvs);
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
list_init(&vg->tags);
|
||||
vg->cmd = cmd;
|
||||
if (!(vg->name = pool_strdup(cmd->mem, ORPHAN))) {
|
||||
log_error("vg name allocation failed");
|
||||
@ -805,6 +810,8 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_init(&pv->tags);
|
||||
|
||||
/* FIXME Move more common code up here */
|
||||
if (!(info->fmt->ops->pv_read(info->fmt, pv_name, pv, mdas))) {
|
||||
log_error("Failed to read existing physical volume '%s'",
|
||||
|
@ -103,6 +103,8 @@ struct physical_volume {
|
||||
uint64_t pe_start;
|
||||
uint32_t pe_count;
|
||||
uint32_t pe_alloc_count;
|
||||
|
||||
struct list tags;
|
||||
};
|
||||
|
||||
struct metadata_area;
|
||||
@ -177,6 +179,8 @@ struct volume_group {
|
||||
/* snapshots */
|
||||
uint32_t snapshot_count;
|
||||
struct list snapshots;
|
||||
|
||||
struct list tags;
|
||||
};
|
||||
|
||||
struct lv_segment {
|
||||
@ -198,6 +202,8 @@ struct lv_segment {
|
||||
uint32_t chunk_size;
|
||||
uint32_t extents_moved;
|
||||
|
||||
struct list tags;
|
||||
|
||||
/* There will be one area for each stripe */
|
||||
struct {
|
||||
area_type_t type;
|
||||
@ -230,6 +236,7 @@ struct logical_volume {
|
||||
uint32_t le_count;
|
||||
|
||||
struct list segments;
|
||||
struct list tags;
|
||||
};
|
||||
|
||||
struct snapshot {
|
||||
|
@ -20,6 +20,7 @@ FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin")
|
||||
FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent")
|
||||
FIELD(LVS, lv, NUM, "Move%", lvid, 6, movepercent, "move_percent")
|
||||
FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv")
|
||||
FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags")
|
||||
|
||||
FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
|
||||
FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
|
||||
@ -30,6 +31,7 @@ FIELD(PVS, pv, STR, "PV", dev, 10, dev_name, "pv_name")
|
||||
FIELD(PVS, pv, STR, "Attr", status, 4, pvstatus, "pv_attr")
|
||||
FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, "pv_pe_count")
|
||||
FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, "pv_pe_alloc_count")
|
||||
FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, "pv_tags")
|
||||
|
||||
FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, "vg_fmt")
|
||||
FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, "vg_uuid")
|
||||
@ -47,6 +49,7 @@ FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, "pv_count")
|
||||
FIELD(VGS, vg, NUM, "#LV", lv_count, 3, uint32, "lv_count")
|
||||
FIELD(VGS, vg, NUM, "#SN", snapshot_count, 3, uint32, "snap_count")
|
||||
FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, "vg_seqno")
|
||||
FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags")
|
||||
|
||||
FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype")
|
||||
FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes")
|
||||
@ -54,4 +57,5 @@ FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", chunk_size, 5, size32, "chunksize")
|
||||
FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start")
|
||||
FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size")
|
||||
FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags")
|
||||
/* *INDENT-ON* */
|
||||
|
@ -128,6 +128,36 @@ static int _dev_name_disp(struct report_handle *rh, struct field *field,
|
||||
return _string_disp(rh, field, &name);
|
||||
}
|
||||
|
||||
static int _tags_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct list *tags = (const struct list *) data;
|
||||
struct str_list *sl;
|
||||
|
||||
if (!pool_begin_object(rh->mem, 256)) {
|
||||
log_error("pool_begin_object failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate_items(sl, tags) {
|
||||
if (!pool_grow_object(rh->mem, sl->str, strlen(sl->str)) ||
|
||||
(sl->list.n != tags && !pool_grow_object(rh->mem, ",", 1))) {
|
||||
log_error("pool_grow_object failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pool_grow_object(rh->mem, "\0", 1)) {
|
||||
log_error("pool_grow_object failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
field->report_string = pool_end_object(rh->mem);
|
||||
field->sort_value = (const void *) field->report_string;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _vgfmt_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
|
@ -26,6 +26,8 @@ arg(units_ARG, '\0', "units", string_arg)
|
||||
arg(nosuffix_ARG, '\0', "nosuffix", NULL)
|
||||
arg(removemissing_ARG, '\0', "removemissing", NULL)
|
||||
arg(abort_ARG, '\0', "abort", NULL)
|
||||
arg(addtag_ARG, '\0', "addtag", tag_arg)
|
||||
arg(deltag_ARG, '\0', "deltag", tag_arg)
|
||||
arg(mknodes_ARG, '\0', "mknodes", NULL)
|
||||
arg(minor_ARG, '\0', "minor", minor_arg)
|
||||
|
||||
|
@ -56,8 +56,10 @@ xx(lvchange,
|
||||
"lvchange\n"
|
||||
"\t[-A|--autobackup y|n]\n"
|
||||
"\t[-a|--available y|n]\n"
|
||||
"\t[--addtag Tag]\n"
|
||||
"\t[-C|--contiguous y|n]\n"
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[--deltag Tag]\n"
|
||||
"\t[-f|--force]\n"
|
||||
"\t[-h|--help]\n"
|
||||
"\t[--ignorelockingfailure]\n"
|
||||
@ -72,12 +74,14 @@ xx(lvchange,
|
||||
|
||||
autobackup_ARG, available_ARG, contiguous_ARG, force_ARG,
|
||||
ignorelockingfailure_ARG, major_ARG, minor_ARG, partial_ARG, permission_ARG,
|
||||
persistent_ARG, readahead_ARG, test_ARG)
|
||||
persistent_ARG, readahead_ARG, addtag_ARG, deltag_ARG,
|
||||
test_ARG)
|
||||
|
||||
xx(lvcreate,
|
||||
"Create a logical volume",
|
||||
"lvcreate " "\n"
|
||||
"\t[-A|--autobackup {y|n}]\n"
|
||||
"\t[--addtag Tag]\n"
|
||||
"\t[-C|--contiguous {y|n}]\n"
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|-?|--help]\n"
|
||||
@ -97,6 +101,7 @@ xx(lvcreate,
|
||||
"lvcreate -s|--snapshot\n"
|
||||
"\t[-c|--chunksize]\n"
|
||||
"\t[-A|--autobackup {y|n}]\n"
|
||||
"\t[--addtag Tag]\n"
|
||||
"\t[-C|--contiguous {y|n}]\n"
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|-?|--help]\n"
|
||||
@ -112,9 +117,10 @@ xx(lvcreate,
|
||||
"\t[--version]\n"
|
||||
"\tOriginalLogicalVolume[Path] [PhysicalVolumePath...]\n\n",
|
||||
|
||||
autobackup_ARG, chunksize_ARG, contiguous_ARG, extents_ARG, major_ARG, minor_ARG,
|
||||
name_ARG, permission_ARG, persistent_ARG, readahead_ARG, size_ARG,
|
||||
snapshot_ARG, stripes_ARG, stripesize_ARG, test_ARG, zero_ARG)
|
||||
autobackup_ARG, chunksize_ARG, contiguous_ARG, extents_ARG, major_ARG,
|
||||
minor_ARG, name_ARG, permission_ARG, persistent_ARG, readahead_ARG, size_ARG,
|
||||
snapshot_ARG, stripes_ARG, stripesize_ARG, addtag_ARG, test_ARG,
|
||||
zero_ARG)
|
||||
|
||||
xx(lvdisplay,
|
||||
"Display information about a logical volume",
|
||||
@ -323,10 +329,13 @@ xx(pvchange,
|
||||
"\t[-u|--uuid]\n"
|
||||
"\t[-x|--allocatable y|n]\n"
|
||||
"\t[-v|--verbose]\n"
|
||||
"\t[--addtag Tag]\n"
|
||||
"\t[--deltag Tag]\n"
|
||||
"\t[--version]" "\n"
|
||||
"\t[PhysicalVolumePath...]\n",
|
||||
|
||||
all_ARG, allocatable_ARG, allocation_ARG, autobackup_ARG, test_ARG, uuid_ARG)
|
||||
all_ARG, allocatable_ARG, allocation_ARG, autobackup_ARG, deltag_ARG,
|
||||
addtag_ARG, test_ARG, uuid_ARG)
|
||||
|
||||
xx(pvcreate,
|
||||
"Initialize physical volume(s) for use by LVM",
|
||||
@ -537,12 +546,14 @@ xx(vgchange,
|
||||
"\t[--version]" "\n"
|
||||
"\t{-a|--available {y|n} |" "\n"
|
||||
"\t -x|--resizeable {y|n} |" "\n"
|
||||
"\t -l|--logicalvolume MaxLogicalVolumes}" "\n"
|
||||
"\t -l|--logicalvolume MaxLogicalVolumes |" "\n"
|
||||
"\t --addtag Tag |\n"
|
||||
"\t --deltag Tag}\n"
|
||||
"\t[VolumeGroupName...]\n",
|
||||
|
||||
allocation_ARG, autobackup_ARG, available_ARG, ignorelockingfailure_ARG,
|
||||
logicalvolume_ARG, partial_ARG, resizeable_ARG, resizable_ARG, test_ARG,
|
||||
uuid_ARG)
|
||||
logicalvolume_ARG, partial_ARG, resizeable_ARG, resizable_ARG, deltag_ARG,
|
||||
addtag_ARG, test_ARG, uuid_ARG)
|
||||
|
||||
xx(vgck,
|
||||
"Check the consistency of volume group(s)",
|
||||
@ -574,6 +585,7 @@ xx(vgcreate,
|
||||
"Create a volume group",
|
||||
"vgcreate" "\n"
|
||||
"\t[-A|--autobackup {y|n}] " "\n"
|
||||
"\t[--addtag Tag] " "\n"
|
||||
"\t[-d|--debug]" "\n"
|
||||
"\t[-h|--help]" "\n"
|
||||
"\t[-l|--maxlogicalvolumes MaxLogicalVolumes]" "\n"
|
||||
@ -586,7 +598,7 @@ xx(vgcreate,
|
||||
"\tVolumeGroupName PhysicalVolume [PhysicalVolume...]\n",
|
||||
|
||||
autobackup_ARG, maxlogicalvolumes_ARG, maxphysicalvolumes_ARG,
|
||||
metadatatype_ARG, physicalextentsize_ARG, test_ARG)
|
||||
metadatatype_ARG, physicalextentsize_ARG, addtag_ARG, test_ARG)
|
||||
|
||||
xx(vgdisplay,
|
||||
"Display volume group information",
|
||||
|
@ -151,19 +151,9 @@ static int lvchange_contiguous(struct cmd_context *cmd,
|
||||
|
||||
backup(lv->vg);
|
||||
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) {
|
||||
log_error("Failed to lock %s", lv->name);
|
||||
vg_revert(lv->vg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No need to suspend LV for this change */
|
||||
if (!vg_commit(lv->vg)) {
|
||||
unlock_lv(cmd, lv->lvid.s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!unlock_lv(cmd, lv->lvid.s)) {
|
||||
log_error("Problem reactivating %s", lv->name);
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -249,8 +239,8 @@ static int lvchange_persistent(struct cmd_context *cmd,
|
||||
log_error("Major number must be specified with -My");
|
||||
return 0;
|
||||
}
|
||||
if (lv_info(lv, &info) && info.exists &&
|
||||
!arg_count(cmd, force_ARG)) {
|
||||
if (lv_info(lv, &info) && info.exists &&
|
||||
!arg_count(cmd, force_ARG)) {
|
||||
if (yes_no_prompt("Logical volume %s will be "
|
||||
"deactivated first. "
|
||||
"Continue? [y/n]: ",
|
||||
@ -301,6 +291,52 @@ static int lvchange_persistent(struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lvchange_tag(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
int arg)
|
||||
{
|
||||
const char *tag;
|
||||
|
||||
if (!(tag = arg_str_value(cmd, arg, NULL))) {
|
||||
log_error("Failed to get tag");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lv->vg->fid->fmt->features & FMT_TAGS)) {
|
||||
log_error("Logical volume %s/%s does not support tags",
|
||||
lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((arg == addtag_ARG)) {
|
||||
if (!str_list_add(cmd->mem, &lv->tags, tag)) {
|
||||
log_error("Failed to add tag %s to %s/%s",
|
||||
tag, lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!str_list_del(&lv->tags, tag)) {
|
||||
log_error("Failed to remove tag %s from %s/%s",
|
||||
tag, lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
|
||||
if (!vg_write(lv->vg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
backup(lv->vg);
|
||||
|
||||
/* No need to suspend LV for this change */
|
||||
if (!vg_commit(lv->vg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle)
|
||||
{
|
||||
@ -368,6 +404,22 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
doit += lvchange_persistent(cmd, lv);
|
||||
}
|
||||
|
||||
/* add tag */
|
||||
if (arg_count(cmd, addtag_ARG)) {
|
||||
if (!archived && !archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
archived = 1;
|
||||
doit += lvchange_tag(cmd, lv, addtag_ARG);
|
||||
}
|
||||
|
||||
/* del tag */
|
||||
if (arg_count(cmd, deltag_ARG)) {
|
||||
if (!archived && !archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
archived = 1;
|
||||
doit += lvchange_tag(cmd, lv, deltag_ARG);
|
||||
}
|
||||
|
||||
if (doit)
|
||||
log_print("Logical volume \"%s\" changed", lv->name);
|
||||
|
||||
@ -384,15 +436,17 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
if (!arg_count(cmd, available_ARG) && !arg_count(cmd, contiguous_ARG)
|
||||
&& !arg_count(cmd, permission_ARG) && !arg_count(cmd, readahead_ARG)
|
||||
&& !arg_count(cmd, minor_ARG) && !arg_count(cmd, major_ARG)
|
||||
&& !arg_count(cmd, persistent_ARG)) {
|
||||
log_error("One or more of -a, -C, -j, -m, -M, -p or -r "
|
||||
"required");
|
||||
&& !arg_count(cmd, persistent_ARG) && !arg_count(cmd, addtag_ARG)
|
||||
&& !arg_count(cmd, deltag_ARG)) {
|
||||
log_error("One or more of -a, -C, -j, -m, -M, -p, -r, "
|
||||
"--addtag or --deltag required");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, ignorelockingfailure_ARG) &&
|
||||
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
|
||||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
|
||||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG) ||
|
||||
arg_count(cmd, addtag_ARG) || arg_count(cmd, deltag_ARG))) {
|
||||
log_error("Only -a permitted with --ignorelockingfailure");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
@ -361,6 +361,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
struct volume_group *vg;
|
||||
struct logical_volume *lv, *org = NULL;
|
||||
struct list *pvh;
|
||||
const char *tag;
|
||||
int consistent = 1;
|
||||
|
||||
if (lp->contiguous)
|
||||
@ -457,9 +458,8 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
status |= LVM_WRITE;
|
||||
}
|
||||
|
||||
if (!(lv = lv_create(vg->fid, lp->lv_name, status, alloc,
|
||||
lp->stripes, lp->stripe_size, lp->extents,
|
||||
vg, pvh)))
|
||||
if (!(lv = lv_create(vg->fid, lp->lv_name, status, alloc, lp->stripes,
|
||||
lp->stripe_size, lp->extents, vg, pvh)))
|
||||
return 0;
|
||||
|
||||
if (lp->read_ahead) {
|
||||
@ -475,6 +475,25 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
lv->minor);
|
||||
}
|
||||
|
||||
if (arg_count(cmd, addtag_ARG)) {
|
||||
if (!(tag = arg_str_value(cmd, addtag_ARG, NULL))) {
|
||||
log_error("Failed to get tag");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lv->vg->fid->fmt->features & FMT_TAGS)) {
|
||||
log_error("Volume group %s does not support tags",
|
||||
lv->vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!str_list_add(cmd->mem, &lv->tags, tag)) {
|
||||
log_error("Failed to add tag %s to %s/%s",
|
||||
tag, lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!archive(vg))
|
||||
return 0;
|
||||
|
||||
|
14
tools/lvm.c
14
tools/lvm.c
@ -243,6 +243,20 @@ int major_arg(struct cmd_context *cmd, struct arg *a)
|
||||
|
||||
int string_arg(struct cmd_context *cmd, struct arg *a)
|
||||
{
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int tag_arg(struct cmd_context *cmd, struct arg *a)
|
||||
{
|
||||
char *pos = a->value;
|
||||
|
||||
if (*pos == '@')
|
||||
pos++;
|
||||
|
||||
if (!validate_name(pos))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -31,13 +31,24 @@ static int _pvchange_single(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
uint64_t sector;
|
||||
|
||||
const char *pv_name = dev_name(pv->dev);
|
||||
const char *tag = NULL;
|
||||
|
||||
int consistent = 1;
|
||||
int allocatable = 0;
|
||||
int tagarg = 0;
|
||||
|
||||
if (arg_count(cmd, addtag_ARG))
|
||||
tagarg = addtag_ARG;
|
||||
else if (arg_count(cmd, deltag_ARG))
|
||||
tagarg = deltag_ARG;
|
||||
|
||||
if (arg_count(cmd, allocatable_ARG))
|
||||
allocatable = !strcmp(arg_str_value(cmd, allocatable_ARG, "n"),
|
||||
"y");
|
||||
else if (tagarg && !(tag = arg_str_value(cmd, tagarg, NULL))) {
|
||||
log_error("Failed to get tag");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If in a VG, must change using volume group. */
|
||||
if (*pv->vg_name) {
|
||||
@ -75,6 +86,12 @@ static int _pvchange_single(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
pv_name, vg->name);
|
||||
return 0;
|
||||
}
|
||||
if (tagarg && !(vg->fid->fmt->features & FMT_TAGS)) {
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
log_error("Volume group containing %s does not "
|
||||
"support tags", pv_name);
|
||||
return 0;
|
||||
}
|
||||
if (arg_count(cmd, uuid_ARG) && lvs_in_vg_activated(vg)) {
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
log_error("Volume group containing %s has active "
|
||||
@ -85,6 +102,11 @@ static int _pvchange_single(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
if (!archive(vg))
|
||||
return 0;
|
||||
} else {
|
||||
if (tagarg) {
|
||||
log_error("Can't change tag on Physical Volume %s not "
|
||||
"in volume group", pv_name);
|
||||
return 0;
|
||||
}
|
||||
if (!lock_vol(cmd, ORPHAN, LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for orphans");
|
||||
return 0;
|
||||
@ -137,6 +159,21 @@ static int _pvchange_single(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
"allocatable", pv_name);
|
||||
pv->status &= ~ALLOCATABLE_PV;
|
||||
}
|
||||
} else if (tagarg) {
|
||||
/* tag or deltag */
|
||||
if ((tagarg == addtag_ARG)) {
|
||||
if (!str_list_add(cmd->mem, &pv->tags, tag)) {
|
||||
log_error("Failed to add tag %s to physical "
|
||||
"volume %s", tag, pv_name);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!str_list_del(&pv->tags, tag)) {
|
||||
log_error("Failed to remove tag %s from "
|
||||
"physical volume" "%s", tag, pv_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* --uuid: Change PV ID randomly */
|
||||
id_create(&pv->id);
|
||||
@ -182,9 +219,10 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
list_init(&mdas);
|
||||
|
||||
if (arg_count(cmd, allocatable_ARG) +
|
||||
+ arg_count(cmd, uuid_ARG) != 1) {
|
||||
log_error("Please give exactly one option of -x or --uuid");
|
||||
if (arg_count(cmd, allocatable_ARG) + arg_count(cmd, addtag_ARG) +
|
||||
arg_count(cmd, deltag_ARG) + arg_count(cmd, uuid_ARG) != 1) {
|
||||
log_error("Please give exactly one option of -x, -uuid, "
|
||||
"--addtag or --deltag");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
|
553
tools/toollib.c
553
tools/toollib.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
* Copyright (C) 2001-2003 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
@ -9,6 +9,7 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct list *arg_lvnames, struct list *tags,
|
||||
void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
struct logical_volume * lv,
|
||||
@ -16,6 +17,10 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
{
|
||||
int ret_max = 0;
|
||||
int ret = 0;
|
||||
int process_all = 0;
|
||||
int process_lv = 0;
|
||||
int tags_supplied = 0;
|
||||
int lvargs_supplied = 0;
|
||||
|
||||
struct lv_list *lvl;
|
||||
|
||||
@ -24,14 +29,47 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (tags && !list_empty(tags))
|
||||
tags_supplied = 1;
|
||||
|
||||
if (arg_lvnames && !list_empty(arg_lvnames))
|
||||
lvargs_supplied = 1;
|
||||
|
||||
/* Process all LVs in this VG if no restrictions given */
|
||||
if (!tags_supplied && !lvargs_supplied)
|
||||
process_all = 1;
|
||||
|
||||
/* Or if VG tags match */
|
||||
if (!process_lv && tags_supplied &&
|
||||
str_list_match_list(tags, &vg->tags))
|
||||
process_all = 1;
|
||||
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
/* Should we process this LV? */
|
||||
if (process_all)
|
||||
process_lv = 1;
|
||||
else
|
||||
process_lv = 0;
|
||||
|
||||
/* LV tag match? */
|
||||
if (!process_lv && tags_supplied &&
|
||||
str_list_match_list(tags, &lvl->lv->tags))
|
||||
process_lv = 1;
|
||||
|
||||
/* LV name match? */
|
||||
if (!process_lv && lvargs_supplied &&
|
||||
str_list_match_item(arg_lvnames, lvl->lv->name))
|
||||
process_lv = 1;
|
||||
|
||||
if (!process_lv)
|
||||
continue;
|
||||
|
||||
ret = process_single(cmd, lvl->lv, handle);
|
||||
if (ret > ret_max)
|
||||
ret_max = ret;
|
||||
}
|
||||
|
||||
return ret_max;
|
||||
|
||||
}
|
||||
|
||||
struct volume_group *recover_vg(struct cmd_context *cmd, const char *vgname,
|
||||
@ -60,26 +98,52 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
|
||||
int opt = 0;
|
||||
int ret_max = 0;
|
||||
int ret = 0;
|
||||
int vg_count = 0;
|
||||
int consistent;
|
||||
|
||||
struct list *slh, *vgnames;
|
||||
struct list *slh, *tags_arg;
|
||||
struct list *vgnames; /* VGs to process */
|
||||
struct str_list *sll;
|
||||
struct volume_group *vg;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
struct list tags, lvnames;
|
||||
struct list arg_lvnames; /* Cmdline vgname or vgname/lvname */
|
||||
char *vglv;
|
||||
size_t vglv_sz;
|
||||
|
||||
const char *vgname;
|
||||
|
||||
list_init(&tags);
|
||||
list_init(&arg_lvnames);
|
||||
|
||||
if (argc) {
|
||||
struct list arg_vgnames;
|
||||
|
||||
log_verbose("Using logical volume(s) on command line");
|
||||
list_init(&arg_vgnames);
|
||||
|
||||
for (; opt < argc; opt++) {
|
||||
char *lv_name = argv[opt];
|
||||
const char *lv_name = argv[opt];
|
||||
char *vgname_def;
|
||||
int vgname_provided = 1;
|
||||
int dev_dir_found = 0;
|
||||
|
||||
/* Do we have a vgname or lvname? */
|
||||
/* Do we have a tag or vgname or lvname? */
|
||||
vgname = lv_name;
|
||||
|
||||
if (*vgname == '@') {
|
||||
if (!validate_name(vgname + 1)) {
|
||||
log_error("Skipping invalid tag %s",
|
||||
vgname);
|
||||
continue;
|
||||
}
|
||||
if (!str_list_add(cmd->mem, &tags,
|
||||
pool_strdup(cmd->mem,
|
||||
vgname + 1))) {
|
||||
log_error("strlist allocation failed");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* FIXME Jumbled parsing */
|
||||
if (*vgname == '/') {
|
||||
while (*vgname == '/')
|
||||
vgname++;
|
||||
@ -94,131 +158,124 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
|
||||
}
|
||||
if (*vgname == '/') {
|
||||
log_error("\"%s\": Invalid path for Logical "
|
||||
"Volume", lv_name);
|
||||
"Volume", argv[opt]);
|
||||
if (ret_max < ECMD_FAILED)
|
||||
ret_max = ECMD_FAILED;
|
||||
continue;
|
||||
}
|
||||
lv_name = vgname;
|
||||
if (strchr(vgname, '/')) {
|
||||
/* Must be an LV */
|
||||
vgname_provided = 0;
|
||||
if (!(vgname = extract_vgname(cmd, lv_name))) {
|
||||
lv_name = strchr(vgname, '/');
|
||||
while (*lv_name == '/')
|
||||
lv_name++;
|
||||
if (!(vgname = extract_vgname(cmd, vgname))) {
|
||||
if (ret_max < ECMD_FAILED)
|
||||
ret_max = ECMD_FAILED;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev_dir_found &&
|
||||
} else if (!dev_dir_found &&
|
||||
(vgname_def = default_vgname(cmd))) {
|
||||
vgname_provided = 0;
|
||||
vgname = vgname_def;
|
||||
}
|
||||
} else
|
||||
lv_name = NULL;
|
||||
|
||||
log_verbose("Finding volume group \"%s\"", vgname);
|
||||
if (!lock_vol(cmd, vgname, lock_type)) {
|
||||
log_error("Can't lock %s: skipping", vgname);
|
||||
continue;
|
||||
}
|
||||
if (lock_type & LCK_WRITE)
|
||||
consistent = 1;
|
||||
else
|
||||
consistent = 0;
|
||||
if (!(vg = vg_read(cmd, vgname, &consistent)) ||
|
||||
!consistent) {
|
||||
unlock_vg(cmd, vgname);
|
||||
if (!vg)
|
||||
log_error("Volume group \"%s\" "
|
||||
"not found", vgname);
|
||||
else
|
||||
log_error("Volume group \"%s\" "
|
||||
"inconsistent", vgname);
|
||||
if (!vg || !(vg =
|
||||
recover_vg(cmd, vgname,
|
||||
lock_type))) {
|
||||
unlock_vg(cmd, vgname);
|
||||
if (ret_max < ECMD_FAILED)
|
||||
ret_max = ECMD_FAILED;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported",
|
||||
vg->name);
|
||||
unlock_vg(cmd, vgname);
|
||||
if (!str_list_add(cmd->mem, &arg_vgnames,
|
||||
pool_strdup(cmd->mem, vgname))) {
|
||||
log_error("strlist allocation failed");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (vgname_provided) {
|
||||
if ((ret =
|
||||
process_each_lv_in_vg(cmd, vg, handle,
|
||||
process_single)) >
|
||||
ret_max)
|
||||
ret_max = ret;
|
||||
unlock_vg(cmd, vgname);
|
||||
continue;
|
||||
if (!lv_name) {
|
||||
if (!str_list_add(cmd->mem, &arg_lvnames,
|
||||
pool_strdup(cmd->mem, vgname))) {
|
||||
log_error("strlist allocation failed");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
} else {
|
||||
vglv_sz = strlen(vgname) + strlen(lv_name) + 2;
|
||||
if (!(vglv = pool_alloc(cmd->mem, vglv_sz)) ||
|
||||
lvm_snprintf(vglv, vglv_sz, "%s/%s", vgname,
|
||||
lv_name) < 0) {
|
||||
log_error("vg/lv string alloc failed");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
if (!str_list_add(cmd->mem, &arg_lvnames,
|
||||
vglv)) {
|
||||
log_error("strlist allocation failed");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(lvl = find_lv_in_vg(vg, lv_name))) {
|
||||
log_error("Can't find logical volume \"%s\" "
|
||||
"in volume group \"%s\"",
|
||||
lv_name, vgname);
|
||||
if (ret_max < ECMD_FAILED)
|
||||
ret_max = ECMD_FAILED;
|
||||
unlock_vg(cmd, vgname);
|
||||
continue;
|
||||
}
|
||||
|
||||
lv = lvl->lv;
|
||||
|
||||
if ((ret = process_single(cmd, lv, handle)) > ret_max)
|
||||
ret_max = ret;
|
||||
unlock_vg(cmd, vgname);
|
||||
}
|
||||
} else {
|
||||
vgnames = &arg_vgnames;
|
||||
}
|
||||
|
||||
if (!argc || !list_empty(&tags)) {
|
||||
log_verbose("Finding all logical volumes");
|
||||
if (!(vgnames = get_vgs(cmd, 0))) {
|
||||
if (!(vgnames = get_vgs(cmd, 0)) || list_empty(vgnames)) {
|
||||
log_error("No volume groups found");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
list_iterate(slh, vgnames) {
|
||||
vgname = list_item(slh, struct str_list)->str;
|
||||
if (!vgname || !*vgname)
|
||||
continue; /* FIXME Unnecessary? */
|
||||
if (!lock_vol(cmd, vgname, lock_type)) {
|
||||
log_error("Can't lock %s: skipping", vgname);
|
||||
}
|
||||
|
||||
list_iterate(slh, vgnames) {
|
||||
vgname = list_item(slh, struct str_list)->str;
|
||||
if (!vgname || !*vgname)
|
||||
continue; /* FIXME Unnecessary? */
|
||||
if (!lock_vol(cmd, vgname, lock_type)) {
|
||||
log_error("Can't lock %s: skipping", vgname);
|
||||
continue;
|
||||
}
|
||||
if (lock_type & LCK_WRITE)
|
||||
consistent = 1;
|
||||
else
|
||||
consistent = 0;
|
||||
if (!(vg = vg_read(cmd, vgname, &consistent)) ||
|
||||
!consistent) {
|
||||
unlock_vg(cmd, vgname);
|
||||
if (!vg)
|
||||
log_error("Volume group \"%s\" "
|
||||
"not found", vgname);
|
||||
else
|
||||
log_error("Volume group \"%s\" "
|
||||
"inconsistent", vgname);
|
||||
if (!vg || !(vg =
|
||||
recover_vg(cmd, vgname,
|
||||
lock_type))) {
|
||||
unlock_vg(cmd, vgname);
|
||||
if (ret_max < ECMD_FAILED)
|
||||
ret_max = ECMD_FAILED;
|
||||
continue;
|
||||
}
|
||||
if (lock_type & LCK_WRITE)
|
||||
consistent = 1;
|
||||
else
|
||||
consistent = 0;
|
||||
if (!(vg = vg_read(cmd, vgname, &consistent)) ||
|
||||
!consistent) {
|
||||
unlock_vg(cmd, vgname);
|
||||
if (!vg)
|
||||
log_error("Volume group \"%s\" "
|
||||
"not found", vgname);
|
||||
else
|
||||
log_error("Volume group \"%s\" "
|
||||
"inconsistent", vgname);
|
||||
if (!vg || !(vg =
|
||||
recover_vg(cmd, vgname,
|
||||
lock_type))) {
|
||||
unlock_vg(cmd, vgname);
|
||||
if (ret_max < ECMD_FAILED)
|
||||
ret_max = ECMD_FAILED;
|
||||
continue;
|
||||
}
|
||||
|
||||
tags_arg = &tags;
|
||||
list_init(&lvnames); /* LVs to be processed in this VG */
|
||||
list_iterate_items(sll, &arg_lvnames) {
|
||||
const char *vg_name = sll->str;
|
||||
const char *lv_name = strchr(vg_name, '/');
|
||||
|
||||
if ((!lv_name && !strcmp(vg_name, vgname))) {
|
||||
/* Process all LVs in this VG */
|
||||
tags_arg = NULL;
|
||||
list_init(&lvnames);
|
||||
break;
|
||||
} else if (!strncmp(vg_name, vgname, strlen(vgname)) &&
|
||||
strlen(vgname) == lv_name - vg_name) {
|
||||
if (!str_list_add(cmd->mem, &lvnames,
|
||||
pool_strdup(cmd->mem,
|
||||
lv_name + 1))) {
|
||||
log_error("strlist allocation failed");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
}
|
||||
ret = process_each_lv_in_vg(cmd, vg, handle,
|
||||
process_single);
|
||||
unlock_vg(cmd, vgname);
|
||||
if (ret > ret_max)
|
||||
ret_max = ret;
|
||||
vg_count++;
|
||||
}
|
||||
|
||||
ret = process_each_lv_in_vg(cmd, vg, &lvnames, tags_arg,
|
||||
handle, process_single);
|
||||
unlock_vg(cmd, vgname);
|
||||
if (ret > ret_max)
|
||||
ret_max = ret;
|
||||
}
|
||||
|
||||
return ret_max;
|
||||
@ -244,6 +301,44 @@ int process_each_segment_in_lv(struct cmd_context *cmd,
|
||||
return ret_max;
|
||||
}
|
||||
|
||||
static int _process_one_vg(struct cmd_context *cmd, const char *vg_name,
|
||||
struct list *tags, struct list *arg_vgnames,
|
||||
int lock_type, int consistent, void *handle,
|
||||
int ret_max,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
const char *vg_name,
|
||||
struct volume_group * vg,
|
||||
int consistent, void *handle))
|
||||
{
|
||||
struct volume_group *vg;
|
||||
int ret = 0;
|
||||
|
||||
if (!lock_vol(cmd, vg_name, lock_type)) {
|
||||
log_error("Can't lock %s: skipping", vg_name);
|
||||
return ret_max;
|
||||
}
|
||||
|
||||
log_verbose("Finding volume group \"%s\"", vg_name);
|
||||
vg = vg_read(cmd, vg_name, &consistent);
|
||||
|
||||
if (!list_empty(tags)) {
|
||||
/* Only process if a tag matches or it's on arg_vgnames */
|
||||
if (!str_list_match_item(arg_vgnames, vg_name) &&
|
||||
!str_list_match_list(tags, &vg->tags)) {
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ret_max;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret = process_single(cmd, vg_name, vg, consistent,
|
||||
handle)) > ret_max)
|
||||
ret_max = ret;
|
||||
|
||||
unlock_vg(cmd, vg_name);
|
||||
|
||||
return ret_max;
|
||||
}
|
||||
|
||||
int process_each_vg(struct cmd_context *cmd, int argc, char **argv,
|
||||
int lock_type, int consistent, void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
@ -253,18 +348,37 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv,
|
||||
{
|
||||
int opt = 0;
|
||||
int ret_max = 0;
|
||||
int ret = 0;
|
||||
|
||||
struct list *slh, *vgnames;
|
||||
struct volume_group *vg;
|
||||
struct str_list *sl;
|
||||
struct list *vgnames;
|
||||
struct list arg_vgnames, tags;
|
||||
|
||||
const char *vg_name;
|
||||
char *dev_dir = cmd->dev_dir;
|
||||
|
||||
list_init(&tags);
|
||||
list_init(&arg_vgnames);
|
||||
|
||||
if (argc) {
|
||||
log_verbose("Using volume group(s) on command line");
|
||||
|
||||
for (; opt < argc; opt++) {
|
||||
vg_name = argv[opt];
|
||||
if (*vg_name == '@') {
|
||||
if (!validate_name(vg_name + 1)) {
|
||||
log_error("Skipping invalid tag %s",
|
||||
vg_name);
|
||||
continue;
|
||||
}
|
||||
if (!str_list_add(cmd->mem, &tags,
|
||||
pool_strdup(cmd->mem,
|
||||
vg_name + 1))) {
|
||||
log_error("strlist allocation failed");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*vg_name == '/') {
|
||||
while (*vg_name == '/')
|
||||
vg_name++;
|
||||
@ -277,46 +391,38 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv,
|
||||
vg_name);
|
||||
continue;
|
||||
}
|
||||
if (!lock_vol(cmd, vg_name, lock_type)) {
|
||||
log_error("Can't lock %s: skipping", vg_name);
|
||||
continue;
|
||||
if (!str_list_add(cmd->mem, &arg_vgnames,
|
||||
pool_strdup(cmd->mem, vg_name))) {
|
||||
log_error("strlist allocation failed");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
log_verbose("Finding volume group \"%s\"", vg_name);
|
||||
vg = vg_read(cmd, vg_name, &consistent);
|
||||
if ((ret = process_single(cmd, vg_name, vg, consistent,
|
||||
handle)) > ret_max)
|
||||
ret_max = ret;
|
||||
unlock_vg(cmd, vg_name);
|
||||
}
|
||||
} else {
|
||||
|
||||
vgnames = &arg_vgnames;
|
||||
}
|
||||
|
||||
if (!argc || !list_empty(&tags)) {
|
||||
log_verbose("Finding all volume groups");
|
||||
if (!(vgnames = get_vgs(cmd, 0)) || list_empty(vgnames)) {
|
||||
log_error("No volume groups found");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
list_iterate(slh, vgnames) {
|
||||
vg_name = list_item(slh, struct str_list)->str;
|
||||
if (!vg_name || !*vg_name)
|
||||
continue; /* FIXME Unnecessary? */
|
||||
if (!lock_vol(cmd, vg_name, lock_type)) {
|
||||
log_error("Can't lock %s: skipping", vg_name);
|
||||
continue;
|
||||
}
|
||||
log_verbose("Finding volume group \"%s\"", vg_name);
|
||||
vg = vg_read(cmd, vg_name, &consistent);
|
||||
ret = process_single(cmd, vg_name, vg, consistent,
|
||||
handle);
|
||||
if (ret > ret_max)
|
||||
ret_max = ret;
|
||||
unlock_vg(cmd, vg_name);
|
||||
}
|
||||
}
|
||||
|
||||
list_iterate_items(sl, vgnames) {
|
||||
vg_name = sl->str;
|
||||
if (!vg_name || !*vg_name)
|
||||
continue; /* FIXME Unnecessary? */
|
||||
ret_max = _process_one_vg(cmd, vg_name, &tags, &arg_vgnames,
|
||||
lock_type, consistent, handle,
|
||||
ret_max, process_single);
|
||||
}
|
||||
|
||||
return ret_max;
|
||||
}
|
||||
|
||||
int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
void *handle,
|
||||
struct list *tags, void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
struct volume_group * vg,
|
||||
struct physical_volume * pv,
|
||||
@ -326,9 +432,13 @@ int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
int ret = 0;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs)
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (tags && !list_empty(tags) &&
|
||||
!str_list_match_list(tags, &pvl->pv->tags))
|
||||
continue;
|
||||
if ((ret = process_single(cmd, vg, pvl->pv, handle)) > ret_max)
|
||||
ret_max = ret;
|
||||
}
|
||||
|
||||
return ret_max;
|
||||
}
|
||||
@ -346,11 +456,33 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
|
||||
|
||||
struct pv_list *pvl;
|
||||
struct physical_volume *pv;
|
||||
struct list *pvslist;
|
||||
struct list *pvslist, *vgnames;
|
||||
struct list tags;
|
||||
struct str_list *sll;
|
||||
char *tagname;
|
||||
int consistent = 1;
|
||||
|
||||
list_init(&tags);
|
||||
|
||||
if (argc) {
|
||||
log_verbose("Using physical volume(s) on command line");
|
||||
for (; opt < argc; opt++) {
|
||||
if (*argv[opt] == '@') {
|
||||
tagname = argv[opt] + 1;
|
||||
|
||||
if (!validate_name(tagname)) {
|
||||
log_error("Skipping invalid tag %s",
|
||||
tagname);
|
||||
continue;
|
||||
}
|
||||
if (!str_list_add(cmd->mem, &tags,
|
||||
pool_strdup(cmd->mem,
|
||||
tagname))) {
|
||||
log_error("strlist allocation failed");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (vg) {
|
||||
if (!(pvl = find_pv_in_vg(vg, argv[opt]))) {
|
||||
log_error("Physical Volume \"%s\" not "
|
||||
@ -374,11 +506,25 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
|
||||
if (ret > ret_max)
|
||||
ret_max = ret;
|
||||
}
|
||||
if (!list_empty(&tags) && (vgnames = get_vgs(cmd, 0)) &&
|
||||
!list_empty(vgnames)) {
|
||||
list_iterate_items(sll, vgnames) {
|
||||
vg = vg_read(cmd, sll->str, &consistent);
|
||||
if (!consistent)
|
||||
continue;
|
||||
ret = process_each_pv_in_vg(cmd, vg, &tags,
|
||||
handle,
|
||||
process_single);
|
||||
if (ret > ret_max)
|
||||
ret_max = ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (vg) {
|
||||
log_verbose("Using all physical volume(s) in "
|
||||
"volume group");
|
||||
ret = process_each_pv_in_vg(cmd, vg, handle, process_single);
|
||||
ret = process_each_pv_in_vg(cmd, vg, NULL, handle,
|
||||
process_single);
|
||||
if (ret > ret_max)
|
||||
ret_max = ret;
|
||||
} else {
|
||||
@ -424,7 +570,7 @@ const char *extract_vgname(struct cmd_context *cmd, const char *lv_name)
|
||||
"Volume", lv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Require exactly one set of consecutive slashes */
|
||||
if ((st = strchr(vg_name, '/')))
|
||||
while (*st == '/')
|
||||
@ -589,13 +735,56 @@ static int _parse_pes(struct pool *mem, char *c, struct list *alloc_areas,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _create_pv_entry(struct pool *mem, struct pv_list *pvl,
|
||||
char *colon, struct list *r)
|
||||
{
|
||||
const char *pvname;
|
||||
struct pv_list *new_pvl;
|
||||
struct list *alloc_areas;
|
||||
|
||||
pvname = dev_name(pvl->pv->dev);
|
||||
if (!(pvl->pv->status & ALLOCATABLE_PV)) {
|
||||
log_error("Physical volume %s not allocatable", pvname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pvl->pv->pe_count == pvl->pv->pe_alloc_count) {
|
||||
log_err("No free extents on physical volume \"%s\"",
|
||||
pvname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(new_pvl = pool_alloc(mem, sizeof(*new_pvl)))) {
|
||||
log_err("Unable to allocate physical volume list.");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(new_pvl, pvl, sizeof(*new_pvl));
|
||||
|
||||
if (!(alloc_areas = pool_alloc(mem, sizeof(*alloc_areas)))) {
|
||||
log_error("Allocation of alloc_areas list failed");
|
||||
return;
|
||||
}
|
||||
list_init(alloc_areas);
|
||||
|
||||
/* Specify which physical extents may be used for allocation */
|
||||
if (!_parse_pes(mem, colon, alloc_areas, pvl->pv->pe_count)) {
|
||||
stack;
|
||||
return;
|
||||
}
|
||||
new_pvl->alloc_areas = alloc_areas;
|
||||
|
||||
list_add(r, &new_pvl->list);
|
||||
}
|
||||
|
||||
struct list *create_pv_list(struct pool *mem,
|
||||
struct volume_group *vg, int argc, char **argv)
|
||||
{
|
||||
struct list *r;
|
||||
struct list *alloc_areas;
|
||||
struct pv_list *pvl, *new_pvl;
|
||||
char *pvname = NULL, *colon;
|
||||
struct pv_list *pvl;
|
||||
struct list tags, arg_pvnames;
|
||||
const char *pvname = NULL;
|
||||
char *colon, *tagname;
|
||||
int i;
|
||||
|
||||
/* Build up list of PVs */
|
||||
@ -605,59 +794,53 @@ struct list *create_pv_list(struct pool *mem,
|
||||
}
|
||||
list_init(r);
|
||||
|
||||
list_init(&tags);
|
||||
list_init(&arg_pvnames);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if ((colon = strchr(argv[i], ':'))) {
|
||||
if (!(pvname = pool_strndup(mem, argv[i],
|
||||
if (*argv[i] == '@') {
|
||||
tagname = argv[i] + 1;
|
||||
if (!validate_name(tagname)) {
|
||||
log_error("Skipping invalid tag %s", tagname);
|
||||
continue;
|
||||
}
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (str_list_match_item(&pvl->pv->tags,
|
||||
tagname)) {
|
||||
_create_pv_entry(mem, pvl, NULL, r);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
pvname = argv[i];
|
||||
|
||||
if ((colon = strchr(pvname, ':'))) {
|
||||
if (!(pvname = pool_strndup(mem, pvname,
|
||||
(unsigned) (colon -
|
||||
argv[i])))) {
|
||||
pvname)))) {
|
||||
log_error("Failed to clone PV name");
|
||||
return NULL;
|
||||
}
|
||||
} else
|
||||
pvname = argv[i];
|
||||
|
||||
if (!(pvl = find_pv_in_vg(vg, pvname))) {
|
||||
log_err("Physical Volume \"%s\" not found in "
|
||||
"Volume Group \"%s\"", pvname, vg->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(pvl->pv->status & ALLOCATABLE_PV)) {
|
||||
log_error("Physical volume %s not allocatable", pvname);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pvl->pv->pe_count == pvl->pv->pe_alloc_count) {
|
||||
log_err("No free extents on physical volume \"%s\"",
|
||||
pvname);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(new_pvl = pool_alloc(mem, sizeof(*new_pvl)))) {
|
||||
log_err("Unable to allocate physical volume list.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(new_pvl, pvl, sizeof(*new_pvl));
|
||||
list_add(r, &new_pvl->list);
|
||||
|
||||
if (!(alloc_areas = pool_alloc(mem, sizeof(*alloc_areas)))) {
|
||||
log_error("Allocation of alloc_areas list failed");
|
||||
return NULL;
|
||||
}
|
||||
list_init(alloc_areas);
|
||||
|
||||
/* Specify which physical extents may be used for allocation */
|
||||
if (!_parse_pes(mem, colon, alloc_areas, pvl->pv->pe_count)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
new_pvl->alloc_areas = alloc_areas;
|
||||
if (!(pvl = find_pv_in_vg(vg, pvname))) {
|
||||
log_err("Physical Volume \"%s\" not found in "
|
||||
"Volume Group \"%s\"", pvname, vg->name);
|
||||
return NULL;
|
||||
}
|
||||
_create_pv_entry(mem, pvl, colon, r);
|
||||
}
|
||||
|
||||
if (list_empty(r))
|
||||
log_error("No specified PVs have space available");
|
||||
|
||||
return list_empty(r) ? NULL : r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
struct list *clone_pv_list(struct pool *mem, struct list *pvsl)
|
||||
{
|
||||
struct list *r;
|
||||
|
@ -59,13 +59,14 @@ int process_each_segment_in_lv(struct cmd_context *cmd,
|
||||
void *handle));
|
||||
|
||||
int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
void *handle,
|
||||
struct list *tags, void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
struct volume_group * vg,
|
||||
struct physical_volume * pv,
|
||||
void *handle));
|
||||
|
||||
int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct list *arg_lvnames, struct list *tags,
|
||||
void *handle,
|
||||
int (*process_single) (struct cmd_context * cmd,
|
||||
struct logical_volume * lv,
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "lvm-file.h"
|
||||
#include "lvm-string.h"
|
||||
#include "pool.h"
|
||||
#include "str_list.h"
|
||||
#include "toolcontext.h"
|
||||
#include "toollib.h"
|
||||
|
||||
@ -104,6 +105,7 @@ int int_arg_with_sign(struct cmd_context *cmd, struct arg *a);
|
||||
int major_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int minor_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int string_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int tag_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int permission_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int metadatatype_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int units_arg(struct cmd_context *cmd, struct arg *a);
|
||||
|
@ -163,6 +163,48 @@ static int _vgchange_logicalvolume(struct cmd_context *cmd,
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
static int _vgchange_tag(struct cmd_context *cmd, struct volume_group *vg,
|
||||
int arg)
|
||||
{
|
||||
const char *tag;
|
||||
|
||||
if (!(tag = arg_str_value(cmd, arg, NULL))) {
|
||||
log_error("Failed to get tag");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg->fid->fmt->features & FMT_TAGS)) {
|
||||
log_error("Volume group %s does not support tags", vg->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!archive(vg))
|
||||
return ECMD_FAILED;
|
||||
|
||||
if ((arg == addtag_ARG)) {
|
||||
if (!str_list_add(cmd->mem, &vg->tags, tag)) {
|
||||
log_error("Failed to add tag %s to volume group %s",
|
||||
tag, vg->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
} else {
|
||||
if (!str_list_del(&vg->tags, tag)) {
|
||||
log_error("Failed to remove tag %s from volume group "
|
||||
"%s", tag, vg->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vg_write(vg) || !vg_commit(vg))
|
||||
return ECMD_FAILED;
|
||||
|
||||
backup(vg);
|
||||
|
||||
log_print("Volume group \"%s\" successfully changed", vg->name);
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
static int _vgchange_uuid(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
struct lv_list *lvl;
|
||||
@ -195,7 +237,7 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
|
||||
struct volume_group *vg, int consistent,
|
||||
void *handle)
|
||||
{
|
||||
int r = 0;
|
||||
int r = ECMD_FAILED;
|
||||
|
||||
if (!vg) {
|
||||
log_error("Unable to find volume group \"%s\"", vg_name);
|
||||
@ -229,6 +271,12 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
|
||||
else if (arg_count(cmd, logicalvolume_ARG))
|
||||
r = _vgchange_logicalvolume(cmd, vg);
|
||||
|
||||
else if (arg_count(cmd, addtag_ARG))
|
||||
r = _vgchange_tag(cmd, vg, addtag_ARG);
|
||||
|
||||
else if (arg_count(cmd, deltag_ARG))
|
||||
r = _vgchange_tag(cmd, vg, deltag_ARG);
|
||||
|
||||
else if (arg_count(cmd, uuid_ARG))
|
||||
r = _vgchange_uuid(cmd, vg);
|
||||
|
||||
@ -239,14 +287,18 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (!
|
||||
(arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
|
||||
arg_count(cmd, resizeable_ARG) + arg_count(cmd, uuid_ARG))) {
|
||||
log_error("One of -a, -l, --uuid or -x options required");
|
||||
arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) +
|
||||
arg_count(cmd, addtag_ARG) + arg_count(cmd, uuid_ARG))) {
|
||||
log_error("One of -a, -l, -x, --addtag, --deltag or --uuid "
|
||||
"options required");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
|
||||
arg_count(cmd, resizeable_ARG) + arg_count(cmd, uuid_ARG) > 1) {
|
||||
log_error("Only one of -a, -l, --uuid or -x options allowed");
|
||||
arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) +
|
||||
arg_count(cmd, addtag_ARG) + arg_count(cmd, uuid_ARG) > 1) {
|
||||
log_error("Only one of -a, -l, -x, --addtag, --deltag or --uuid"
|
||||
" options allowed");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
char *vg_name;
|
||||
char vg_path[PATH_MAX];
|
||||
struct volume_group *vg;
|
||||
const char *tag;
|
||||
|
||||
if (!argc) {
|
||||
log_error("Please provide volume group name and "
|
||||
@ -108,6 +109,24 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
log_error("Warning: Setting maxphysicalvolumes to %d "
|
||||
"(0 means unlimited)", vg->max_pv);
|
||||
|
||||
if (arg_count(cmd, addtag_ARG)) {
|
||||
if (!(tag = arg_str_value(cmd, addtag_ARG, NULL))) {
|
||||
log_error("Failed to get tag");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg->fid->fmt->features & FMT_TAGS)) {
|
||||
log_error("Volume group format does not support tags");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!str_list_add(cmd->mem, &vg->tags, tag)) {
|
||||
log_error("Failed to add tag %s to volume group %s",
|
||||
tag, vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lock_vol(cmd, "", LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for orphan PVs");
|
||||
return ECMD_FAILED;
|
||||
|
@ -51,10 +51,11 @@ static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name,
|
||||
if (arg_count(cmd, verbose_ARG)) {
|
||||
vgdisplay_extents(vg);
|
||||
|
||||
process_each_lv_in_vg(cmd, vg, NULL, &lvdisplay_full);
|
||||
process_each_lv_in_vg(cmd, vg, NULL, NULL, NULL,
|
||||
&lvdisplay_full);
|
||||
|
||||
log_print("--- Physical volumes ---");
|
||||
process_each_pv_in_vg(cmd, vg, NULL, &pvdisplay_short);
|
||||
process_each_pv_in_vg(cmd, vg, NULL, NULL, &pvdisplay_short);
|
||||
}
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
|
Loading…
Reference in New Issue
Block a user