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 \
list_init(&vg->pvs);
list_init(&vg->lvs);
list_init(&vg->snapshots);
+ list_init(&vg->tags);
if (!_check_vgs(pvs, &partial))
goto bad;
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
pv->pe_count = pvd->pe_total;
pv->pe_alloc_count = pvd->pe_allocated;
+ list_init(&pv->tags);
+
return 1;
}
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);
lv->le_count = lvd->lv_allocated_le;
list_init(&lv->segments);
+ list_init(&lv->tags);
return 1;
}
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;
_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;
{
struct list *pvh;
struct physical_volume *pv;
- char buffer[256];
+ char buffer[4096];
const char *name;
_outf(f, "physical_volumes {");
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)) {
unsigned int s;
const char *name;
const char *type;
+ char buffer[4096];
_outf(f, "segment%u {", count);
_inc_indent(f);
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);
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;
struct list *lvh;
struct logical_volume *lv;
struct lv_segment *seg;
- char buffer[256];
+ char buffer[4096];
int seg_count;
/*
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));
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");
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);
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;
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;
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++;
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)) {
--- /dev/null
+/*
+ * 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;
+}
return NULL;
}
+ list_init(&seg->tags);
+
return seg;
}
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;
#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
return 0;
}
+ if (!str_list_lists_equal(&first->tags, &second->tags))
+ return 0;
+
return 1;
}
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;
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");
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,
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");
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'",
uint64_t pe_start;
uint32_t pe_count;
uint32_t pe_alloc_count;
+
+ struct list tags;
};
struct metadata_area;
/* snapshots */
uint32_t snapshot_count;
struct list snapshots;
+
+ struct list tags;
};
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;
uint32_t le_count;
struct list segments;
+ struct list tags;
};
struct snapshot {
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")
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")
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")
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* */
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)
{
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)
"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"
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"
"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"
"\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",
"\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",
"\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)",
"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"
"\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",
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;
}
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]: ",
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)
{
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);
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;
}
struct volume_group *vg;
struct logical_volume *lv, *org = NULL;
struct list *pvh;
+ const char *tag;
int consistent = 1;
if (lp->contiguous)
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) {
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;
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;
}
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) {
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 "
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;
"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);
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;
}
/*
- * Copyright (C) 2001 Sistina Software (UK) Limited.
+ * Copyright (C) 2001-2003 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
#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,
{
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;
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,
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++;
}
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 (!(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;
+ 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;
+ }
}
-
- 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);
- continue;
- }
- if (lock_type & LCK_WRITE)
- consistent = 1;
+ }
+
+ 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
- consistent = 0;
- if (!(vg = vg_read(cmd, vgname, &consistent)) ||
- !consistent) {
+ log_error("Volume group \"%s\" "
+ "inconsistent", vgname);
+ if (!vg || !(vg =
+ recover_vg(cmd, vgname,
+ lock_type))) {
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 (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;
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,
{
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++;
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,
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;
}
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 "
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 {
"Volume", lv_name);
return 0;
}
-
+
/* Require exactly one set of consecutive slashes */
if ((st = strchr(vg_name, '/')))
while (*st == '/')
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 */
}
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],
- (unsigned) (colon -
- argv[i])))) {
- log_error("Failed to clone PV name");
- return NULL;
+ 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);
+ }
}
- } 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);
+ pvname = argv[i];
- if (!(alloc_areas = pool_alloc(mem, sizeof(*alloc_areas)))) {
- log_error("Allocation of alloc_areas list failed");
- return NULL;
+ if ((colon = strchr(pvname, ':'))) {
+ if (!(pvname = pool_strndup(mem, pvname,
+ (unsigned) (colon -
+ pvname)))) {
+ log_error("Failed to clone PV name");
+ 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;
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,
#include "lvm-file.h"
#include "lvm-string.h"
#include "pool.h"
+#include "str_list.h"
#include "toolcontext.h"
#include "toollib.h"
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);
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;
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);
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);
{
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;
}
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 "
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;
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;