summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--WHATS_NEW1
-rw-r--r--lib/format_text/format-text.c2
-rw-r--r--lib/format_text/layout.h2
-rw-r--r--lib/metadata/metadata.h15
-rw-r--r--lib/metadata/pv_manip.c95
-rw-r--r--man/Makefile.in8
-rw-r--r--tools/Makefile.in1
-rw-r--r--tools/commands.h13
-rw-r--r--tools/pvresize.c221
-rw-r--r--tools/stub.h1
10 files changed, 348 insertions, 11 deletions
diff --git a/WHATS_NEW b/WHATS_NEW
index 3a032d19..24b659ed 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.00 -
===================================
+ A pvresize implementation.
Fix contiguous allocation when there are no preceding segments.
Add mirror_seg pointer to lv_segment struct.
Only keep a device open if it's known to belong to a locked VG.
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 9c605b1f..01a7e5ce 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -1687,7 +1687,7 @@ struct format_type *create_text_format(struct cmd_context *cmd)
fmt->name = FMT_TEXT_NAME;
fmt->alias = FMT_TEXT_ALIAS;
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_PRECOMMIT |
- FMT_UNLIMITED_VOLS;
+ FMT_UNLIMITED_VOLS | FMT_RESIZE_PV;
if (!(mda_lists = dm_malloc(sizeof(struct mda_lists)))) {
log_error("Failed to allocate dir_list");
diff --git a/lib/format_text/layout.h b/lib/format_text/layout.h
index 2f7ec8bc..2f8c9bce 100644
--- a/lib/format_text/layout.h
+++ b/lib/format_text/layout.h
@@ -37,6 +37,8 @@ struct data_area_list {
/* On disk */
struct pv_header {
uint8_t pv_uuid[ID_LEN];
+
+ /* This size can be overridden if PV belongs to a VG */
uint64_t device_size_xl; /* Bytes */
/* NULL-terminated list of data areas followed by */
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index 1d162531..6820af07 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -58,6 +58,7 @@
#define MIRROR_LOG 0x00020000 /* LV */
#define MIRROR_IMAGE 0x00040000 /* LV */
#define ACTIVATE_EXCL 0x00080000 /* LV - internal use only */
+#define PRECOMMITTED 0x00100000 /* VG - internal use only */
#define LVM_READ 0x00000100 /* LV VG */
#define LVM_WRITE 0x00000200 /* LV VG */
@@ -72,6 +73,7 @@
#define FMT_RESTRICTED_LVIDS 0x00000010 /* LVID <= 255 */
#define FMT_ORPHAN_ALLOCATABLE 0x00000020 /* Orphan PV allocatable? */
#define FMT_PRECOMMIT 0x00000040 /* Supports pre-commit? */
+#define FMT_RESIZE_PV 0x00000080 /* Supports pvresize? */
typedef enum {
ALLOC_INVALID,
@@ -402,10 +404,10 @@ int vg_commit(struct volume_group *vg);
int vg_revert(struct volume_group *vg);
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
int *consistent);
-struct volume_group *vg_read_precommitted(struct cmd_context *cmd,
- const char *vg_name,
- int *consistent);
-struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid);
+// struct volume_group *vg_read_precommitted(struct cmd_context *cmd,
+// const char *vg_name,
+// int *consistent);
+// struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid);
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
struct list *mdas, uint64_t *label_sector,
int warnings);
@@ -428,6 +430,8 @@ struct physical_volume *pv_create(const struct format_type *fmt,
uint32_t existing_extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list *mdas);
+int pv_resize(struct physical_volume *pv, struct volume_group *vg,
+ uint32_t new_pe_count);
struct volume_group *vg_create(struct cmd_context *cmd, const char *name,
uint32_t extent_size, uint32_t max_pv,
@@ -491,7 +495,8 @@ struct volume_group *find_vg_with_lv(const char *lv_name);
/* Find LV with given lvid (used during activation) */
struct logical_volume *lv_from_lvid(struct cmd_context *cmd,
- const char *lvid_s);
+ const char *lvid_s,
+ int precommit);
/* FIXME Merge these functions with ones above */
struct physical_volume *find_pv(struct volume_group *vg, struct device *dev);
diff --git a/lib/metadata/pv_manip.c b/lib/metadata/pv_manip.c
index f5d3045e..6c27a730 100644
--- a/lib/metadata/pv_manip.c
+++ b/lib/metadata/pv_manip.c
@@ -301,3 +301,98 @@ int check_pv_segments(struct volume_group *vg)
return ret;
}
+
+static int _reduce_pv(struct physical_volume *pv, struct volume_group *vg, uint32_t new_pe_count)
+{
+ struct pv_segment *peg, *pegt;
+ uint32_t old_pe_count = pv->pe_count;
+
+ if (new_pe_count < pv->pe_alloc_count) {
+ log_error("%s: cannot resize to %" PRIu32 " extents "
+ "as %" PRIu32 " are allocated.",
+ dev_name(pv->dev), new_pe_count,
+ pv->pe_alloc_count);
+ return 0;
+ }
+
+ /* Check PEs to be removed are not already allocated */
+ list_iterate_items(peg, &pv->segments) {
+ if (peg->pe + peg->len <= new_pe_count)
+ continue;
+
+ if (peg->lvseg) {
+ log_error("%s: cannot resize to %" PRIu32 " extents as "
+ "later ones are allocated.",
+ dev_name(pv->dev), new_pe_count);
+ return 0;
+ }
+ }
+
+ if (!pv_split_segment(pv, new_pe_count)) {
+ stack;
+ return 0;
+ }
+
+ list_iterate_items_safe(peg, pegt, &pv->segments) {
+ if (peg->pe + peg->len > new_pe_count)
+ list_del(&peg->list);
+ }
+
+ pv->pe_count = new_pe_count;
+
+ vg->extent_count -= (old_pe_count - new_pe_count);
+ vg->free_count -= (old_pe_count - new_pe_count);
+
+ return 1;
+}
+
+static int _extend_pv(struct physical_volume *pv, struct volume_group *vg,
+ uint32_t new_pe_count)
+{
+ struct pv_segment *peg;
+ uint32_t old_pe_count = pv->pe_count;
+
+ if ((uint64_t) new_pe_count * pv->pe_size > pv->size ) {
+ log_error("%s: cannot resize to %" PRIu32 " extents as there "
+ "is only room for %" PRIu64 ".", dev_name(pv->dev),
+ new_pe_count, pv->size / pv->pe_size);
+ return 0;
+ }
+
+ peg = _alloc_pv_segment(pv->fmt->cmd->mem, pv,
+ old_pe_count,
+ new_pe_count - old_pe_count,
+ NULL, 0);
+ list_add(&pv->segments, &peg->list);
+
+ pv->pe_count = new_pe_count;
+
+ vg->extent_count += (new_pe_count - old_pe_count);
+ vg->free_count += (new_pe_count - old_pe_count);
+
+ return 1;
+}
+
+/*
+ * Resize a PV in a VG, adding or removing segments as needed.
+ * New size must fit within pv->size.
+ */
+int pv_resize(struct physical_volume *pv,
+ struct volume_group *vg,
+ uint32_t new_pe_count)
+{
+ if ((new_pe_count == pv->pe_count)) {
+ log_verbose("No change to size of physical volume %s.",
+ dev_name(pv->dev));
+ return 1;
+ }
+
+ log_verbose("Resizing physical volume %s from %" PRIu32
+ " to %" PRIu32 " extents.",
+ dev_name(pv->dev), pv->pe_count, new_pe_count);
+
+ if (new_pe_count > pv->pe_count)
+ return _extend_pv(pv, vg, new_pe_count);
+ else
+ return _reduce_pv(pv, vg, new_pe_count);
+}
diff --git a/man/Makefile.in b/man/Makefile.in
index 1df58458..4b2e291c 100644
--- a/man/Makefile.in
+++ b/man/Makefile.in
@@ -19,10 +19,10 @@ VPATH = @srcdir@
MAN5=lvm.conf.5
MAN8=lvchange.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 lvmchange.8 \
lvmdiskscan.8 lvreduce.8 lvremove.8 lvrename.8 lvresize.8 lvs.8 \
- lvscan.8 pvchange.8 pvcreate.8 pvdisplay.8 pvmove.8 pvremove.8 pvs.8 \
- pvscan.8 vgcfgbackup.8 vgcfgrestore.8 vgchange.8 vgck.8 vgcreate.8 \
- vgconvert.8 vgdisplay.8 vgexport.8 vgextend.8 vgimport.8 \
- vgmerge.8 vgmknodes.8 vgreduce.8 vgremove.8 vgrename.8 \
+ lvscan.8 pvchange.8 pvcreate.8 pvdisplay.8 pvmove.8 pvremove.8 \
+ pvresize.8 pvs.8 pvscan.8 vgcfgbackup.8 vgcfgrestore.8 vgchange.8 \
+ vgck.8 vgcreate.8 vgconvert.8 vgdisplay.8 vgexport.8 vgextend.8 \
+ vgimport.8 vgmerge.8 vgmknodes.8 vgreduce.8 vgremove.8 vgrename.8 \
vgs.8 vgscan.8 vgsplit.8
MAN8CLUSTER=clvmd.8
MAN5DIR=${mandir}/man5
diff --git a/tools/Makefile.in b/tools/Makefile.in
index 471cb02e..b4b17606 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -42,6 +42,7 @@ SOURCES =\
pvdisplay.c \
pvmove.c \
pvremove.c \
+ pvresize.c \
pvscan.c \
reporter.c \
segtypes.c \
diff --git a/tools/commands.h b/tools/commands.h
index c5b212e6..1adfd724 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -373,6 +373,19 @@ xx(pvchange,
all_ARG, allocatable_ARG, allocation_ARG, autobackup_ARG, deltag_ARG,
addtag_ARG, test_ARG, uuid_ARG)
+xx(pvresize,
+ "Resize physical volume(s)",
+ "pvresize " "\n"
+ "\t[-d|--debug]" "\n"
+ "\t[-h|-?|--help] " "\n"
+ "\t[--setphysicalvolumesize PhysicalVolumeSize[kKmMgGtT]" "\n"
+ "\t[-t|--test] " "\n"
+ "\t[-v|--verbose] " "\n"
+ "\t[--version] " "\n"
+ "\tPhysicalVolume [PhysicalVolume...]\n",
+
+ physicalvolumesize_ARG, test_ARG)
+
xx(pvcreate,
"Initialize physical volume(s) for use by LVM",
"pvcreate " "\n"
diff --git a/tools/pvresize.c b/tools/pvresize.c
new file mode 100644
index 00000000..0a73fcef
--- /dev/null
+++ b/tools/pvresize.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2005 Zak Kipling. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "tools.h"
+
+struct pvresize_params {
+ uint64_t new_size;
+
+ unsigned done;
+ unsigned total;
+};
+
+static int _pvresize_single(struct cmd_context *cmd,
+ struct volume_group *vg,
+ struct physical_volume *pv,
+ void *handle)
+{
+ struct pv_list *pvl;
+ int consistent = 1;
+ uint64_t size = 0;
+ uint32_t new_pe_count = 0;
+ struct list mdas;
+ const char *pv_name = dev_name(pv->dev);
+ struct pvresize_params *params = (struct pvresize_params *) handle;
+ const char *vg_name;
+
+ list_init(&mdas);
+
+ params->total++;
+
+ if (!*pv->vg_name) {
+ vg_name = ORPHAN;
+
+ if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
+ log_error("Can't get lock for orphans");
+ return ECMD_FAILED;
+ }
+
+ if (!(pv = pv_read(cmd, pv_name, &mdas, NULL, 1))) {
+ unlock_vg(cmd, vg_name);
+ log_error("Unable to read PV \"%s\"", pv_name);
+ return ECMD_FAILED;
+ }
+
+ /* FIXME Create function to test compatibility properly */
+ if (list_size(&mdas) > 1) {
+ log_error("%s: too many metadata areas for pvresize",
+ pv_name);
+ unlock_vg(cmd, vg_name);
+ return ECMD_FAILED;
+ }
+ } else {
+ vg_name = pv->vg_name;
+
+ if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
+ log_error("Can't get lock for %s", pv->vg_name);
+ return ECMD_FAILED;
+ }
+
+ if (!(vg = vg_read(cmd, vg_name, &consistent))) {
+ unlock_vg(cmd, vg_name);
+ log_error("Unable to find volume group of \"%s\"",
+ pv_name);
+ return ECMD_FAILED;
+ }
+
+ if (vg->status & EXPORTED_VG) {
+ unlock_vg(cmd, vg_name);
+ log_error("Volume group \"%s\" is exported", vg->name);
+ return ECMD_FAILED;
+ }
+
+ if (!(vg->status & LVM_WRITE)) {
+ unlock_vg(cmd, pv->vg_name);
+ log_error("Volume group \"%s\" is read-only", vg->name);
+ return ECMD_FAILED;
+ }
+
+ if (!(pvl = find_pv_in_vg(vg, pv_name))) {
+ unlock_vg(cmd, vg_name);
+ log_error("Unable to find \"%s\" in volume group \"%s\"",
+ pv_name, vg->name);
+ return ECMD_FAILED;
+ }
+
+ pv = pvl->pv;
+
+ if (!archive(vg))
+ return ECMD_FAILED;
+ }
+
+ if (!(pv->fmt->features & FMT_RESIZE_PV)) {
+ log_error("Physical volume %s format does not support resizing.",
+ pv_name);
+ unlock_vg(cmd, vg_name);
+ return ECMD_FAILED;
+ }
+
+ /* Get new size */
+ if (!dev_get_size(pv->dev, &size)) {
+ log_error("%s: Couldn't get size.", pv_name);
+ unlock_vg(cmd, vg_name);
+ return ECMD_FAILED;
+ }
+
+ if (params->new_size) {
+ if (params->new_size > size)
+ log_print("WARNING: %s: Overriding real size. "
+ "You could lose data.", pv_name);
+ log_verbose("%s: Pretending size is %" PRIu64 " not %" PRIu64
+ " sectors.", pv_name, params->new_size, pv->size);
+ size = params->new_size;
+ }
+
+ if (size < PV_MIN_SIZE) {
+ log_error("%s: Size must exceed minimum of %ld sectors.",
+ pv_name, PV_MIN_SIZE);
+ unlock_vg(cmd, vg_name);
+ return ECMD_FAILED;
+ }
+
+ if (size < pv->pe_start) {
+ log_error("%s: Size must exceed physical extent start of "
+ "%" PRIu64 " sectors.", pv_name, pv->pe_start);
+ unlock_vg(cmd, vg_name);
+ return ECMD_FAILED;
+ }
+
+ pv->size = size;
+
+ if (vg) {
+ pv->size -= pv->pe_start;
+ new_pe_count = pv->size / vg->extent_size;
+
+ if (!new_pe_count) {
+ log_error("%s: Size must leave space for at "
+ "least one physical extent of "
+ "%" PRIu32 " sectors.", pv_name,
+ pv->pe_size);
+ unlock_vg(cmd, vg_name);
+ return ECMD_FAILED;
+ }
+
+ if (!pv_resize(pv, vg, new_pe_count)) {
+ stack;
+ unlock_vg(cmd, vg_name);
+ return ECMD_FAILED;
+ }
+ }
+
+ log_verbose("Resizing volume \"%s\" to %" PRIu64 " sectors.",
+ pv_name, pv->size);
+
+ log_verbose("Updating physical volume \"%s\"", pv_name);
+ if (*pv->vg_name) {
+ if (!vg_write(vg) || !vg_commit(vg)) {
+ unlock_vg(cmd, pv->vg_name);
+ log_error("Failed to store physical volume \"%s\" in "
+ "volume group \"%s\"", pv_name, vg->name);
+ return ECMD_FAILED;
+ }
+ backup(vg);
+ unlock_vg(cmd, vg_name);
+ } else {
+ if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
+ unlock_vg(cmd, ORPHAN);
+ log_error("Failed to store physical volume \"%s\"",
+ pv_name);
+ return ECMD_FAILED;
+ }
+ unlock_vg(cmd, vg_name);
+ }
+
+ log_print("Physical volume \"%s\" changed", pv_name);
+
+ params->done++;
+
+ return 1;
+}
+
+int pvresize(struct cmd_context *cmd, int argc, char **argv)
+{
+ struct pvresize_params params;
+ int ret;
+
+ if (!argc) {
+ log_error("Please supply physical volume(s)");
+ return EINVALID_CMD_LINE;
+ }
+
+ if (arg_sign_value(cmd, physicalvolumesize_ARG, 0) == SIGN_MINUS) {
+ log_error("Physical volume size may not be negative");
+ return 0;
+ }
+
+ params.new_size = arg_uint64_value(cmd, physicalvolumesize_ARG,
+ UINT64_C(0)) * 2;
+
+ params.done = 0;
+ params.total = 0;
+
+ ret = process_each_pv(cmd, argc, argv, NULL, &params, _pvresize_single);
+
+ log_print("%d physical volume(s) resized / %d physical volume(s) "
+ "not resized", params.done, params.total - params.done);
+
+ return ret;
+}
diff --git a/tools/stub.h b/tools/stub.h
index e38ddb78..61b0a98e 100644
--- a/tools/stub.h
+++ b/tools/stub.h
@@ -19,7 +19,6 @@
/*int e2fsadm(struct cmd_context *cmd, int argc, char **argv) unimplemented*/
int lvmsadc(struct cmd_context *cmd, int argc, char **argv) unimplemented
int lvmsar(struct cmd_context *cmd, int argc, char **argv) unimplemented
-int pvresize(struct cmd_context *cmd, int argc, char **argv) unimplemented
int pvdata(struct cmd_context *cmd, int argc, char **argv) {
log_error("There's no 'pvdata' command in LVM2.");