1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-10 05:18:36 +03:00
This commit is contained in:
Alasdair Kergon 2004-03-08 17:19:15 +00:00
parent 6dbf31c0c3
commit b89c4e9002
26 changed files with 842 additions and 237 deletions

View File

@ -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 \

View File

@ -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;

View File

@ -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;
}

View File

@ -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));

View File

@ -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");

View File

@ -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);

View File

@ -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
View 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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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'",

View File

@ -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 {

View File

@ -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* */

View File

@ -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)
{

View File

@ -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)

View File

@ -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",

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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;