#include <sys/types.h>
#include "dev-cache.h"
#include "list.h"
-#include "lvm-types.h"
-
#define ID_LEN 32
#define NAME_LEN 128
/* Various flags */
/* Note that the bits no longer necessarily correspond to LVM1 disk format */
-#define STATUS_ACTIVE 0x01 /* PV VG LV */
-
-#define STATUS_EXPORTED 0x02 /* VG */
-#define STATUS_EXTENDABLE 0x04 /* VG */
-
-#define STATUS_ALLOCATED 0x02 /* PV */
-
-#define STATUS_SPINDOWN 0x02 /* LV */
-#define STATUS_BADBLOCK_ON 0x04 /* LV */
-#define STATUS_ALLOC_STRICT 0x08 /* LV */
-#define STATUS_ALLOC_CONTIGUOUS 0x10 /* LV */
-
-#define ACCESS_READ 0x01 /* LV VG */
-#define ACCESS_WRITE 0x02 /* LV VG */
+/* Status bits */
+#define ST_ACTIVE 0x01 /* PV VG LV */
+#define ST_EXPORTED_VG 0x02 /* VG */ /* And PV too perhaps? */
+#define ST_EXTENDABLE_VG 0x04 /* VG */
+#define ST_ALLOCATED_PV 0x08 /* PV */
+#define ST_SPINDOWN_LV 0x10 /* LV */
-#define ACCESS_SNAPSHOT 0x04 /* LV */
-#define ACCESS_SNAPSHOT_ORG 0x08 /* LV */
+/* Access bits */
+#define AC_READ 0x01 /* LV VG */
+#define AC_WRITE 0x02 /* LV VG */
+#define AC_CLUSTERED 0x04 /* VG */
+#define AC_SHARED 0x08 /* VG */
-#define ACCESS_CLUSTERED 0x04 /* VG */
-#define ACCESS_SHARED 0x08 /* VG */
+/* LV Flags */
+#define LV_ALLOC_STRICT 0x01 /* LV */
+#define LV_ALLOC_CONTIGUOUS 0x02 /* LV */
+#define LV_SNAPSHOT 0x04 /* LV */
+#define LV_SNAPSHOT_ORG 0x08 /* LV */
+#define LV_BADBLOCK_ON 0x10 /* LV */
struct id *id;
char *name;
- uint32_t access;
uint32_t status;
+ uint32_t access;
+ uint32_t flags;
uint32_t open;
uint64_t size;
struct logical_volume **lv;
};
-struct string_list {
+struct name_list {
struct list_head list;
- char * string;
+ char * name;
};
struct pv_list {
/* ownership of returned objects passes */
struct io_space {
- struct string_list *(*get_vgs)(struct io_space *is);
+ /* Returns list of names of all vgs */
+ struct name_list *(*get_vgs)(struct io_space *is);
+
+ /* Returns list of fully-populated pv structures */
struct pv_list *(*get_pvs)(struct io_space *is);
+ /* Return PV with given name (may be full or relative path) */
struct physical_volume *(*pv_read)(struct io_space *is,
- struct device *dev);
+ const char *pv_name);
+
+ /* Write a PV structure to disk. */
+ /* Fails if the PV is in a VG ie vg_name filled on the disk or in *pv */
int (*pv_write)(struct io_space *is, struct physical_volume *pv);
+ /* vg_name may contain slash(es) - if not, this function adds prefix */
+ /* Default prefix is '/dev/' but can be changed from config file? */
+ /* (via a prefix_set() ?) */
struct volume_group *(*vg_read)(struct io_space *is,
const char *vg_name);
+
+ /* Write out complete VG metadata. */
+ /* Ensure (& impose?) consistency before writing anything.
+ * eg. PEs can't refer to PVs not part of the VG
+ * Order write sequence to aid recovery if process is aborted
+ * (eg flush entire set of changes to each disk in turn?)
+ * If overwriting existing VG data, needs to check for any PVs
+ * removed from the VG and update those PVs too. If those PVs
+ * are no longer in use, blank out vg_name on them. Otherwise
+ * set vg_name to something temporary and unique - this must be
+ * a vgsplit with another vg_write() about to follow (or set a new
+ * status flag?)
+ * OR Should all consistency checks on the *_write*
+ * functions here be handled by a wrapper around them, so that they
+ * *are* capable of leaving the system in an unusable state?
+ * OR Should vgsplit set flags to modify vg_write behaviour,
+ * even specifying the new vg_name to insert?
+ */
int (*vg_write)(struct io_space *is, struct volume_group *vg);
+
void (*destroy)(struct io_space *is);
struct dev_filter *filter;
void *private;
+ /* Something here to allow repair tools & --force options to */
+ /* set flags to override certain consistency checks */
+ /* eg. in _write functions to allow restoration of metadata */
+ /* & in _read functions to allow "gaps" and specify which of */
+ /* conflicting copies of metadata to use (device restriction?) */
};
/* FIXME: Move to other files */
const char *text_file);
struct io_space *create_lvm_v1_format(struct dev_filter *filter);
+inline int write_backup(struct io_space *orig, struct io_space *text)
+{
+
+}
+
+
int id_eq(struct id *op1, struct id *op2);
+/* Create consistent new empty structures, populated with defaults */
struct volume_group *vg_create();
struct physical_volume *pv_create();
int vg_destroy(struct volume_group *vg);
+/* Manipulate PV structures */
int pv_add(struct volume_group *vg, struct physical_volume *pv);
int pv_remove(struct volume_group *vg, struct physical_volume *pv);
struct physical_volume *pv_find(struct volume_group *vg,
const char *pv_name);
+/* Add an LV to a given VG */
int lv_add(struct volume_group *vg, struct logical_volume *lv);
+
+/* Remove an LV from a given VG */
int lv_remove(struct volume_group *vg, struct logical_volume *lv);
-struct logical_volume *lv_find(struct volume_group *vg,
- const char *lv_name);
+
+/* Return the VG that contains a given LV (based on path given in lv_name) */
+/* (or environment var?) */
+struct volume_group *vg_find(const char *lv_name);
+
+/* Find an LV within a given VG */
+struct logical_volume *lv_find(struct volume_group *vg, const char *lv_name);
#endif
*
*/
-#ifndef _LVM_ERROR_H_INCLUDE
-#define _LVM_ERROR_H_INCLUDE
+#ifndef _LVM_ERRORS_H
+#define _LVM_ERRORS_H
-#define LVM_EINVALID_CMD_LINE 1
-#define LVM_ENOMEM 2
-#define LVM_ENO_SUCH_CMD 3
-#define LVM_ECMD_PROCESSED 4
-#define LVM_ECMD_FAILED 5
+#define EINVALID_CMD_LINE 1
+#define ENO_SUCH_CMD 3
+#define ECMD_PROCESSED 4
+#define ECMD_FAILED 5
#endif /* #ifndef _LVM_ERROR_H_INCLUDE */
if (argc < 2) {
log_error("please enter logical volume & physical volume(s)");
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
lv_name = argv[0];
if (argc == 0) {
log_error("please enter a logical volume path");
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
for (opt = 0; opt < argc; opt++) {
ios = active_ios();
- if ((ret = lv_check_name(lv_name)) < 0) {
- return LVM_ECMD_FAILED;
- }
-
lv_name = lvm_check_default_vg_name(lv_name, buffer, sizeof (buffer));
/* does VG exist? */
vg_name = vg_name_of_lv(lv_name);
log_verbose("Finding volume group %s", vg_name);
if (!(vg = ios->vg_read(ios, vg_name))) {
log_error("volume group %s doesn't exist", vg_name);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
if (!(vg->status & STATUS_ACTIVE)) {
log_error("volume group %s must be active before removing "
"logical volume", vg_name);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
if (!(lv = lv_find(vg, lv_name))) {
log_error("can't find logical volume %s in volume group %s",
lv_name, vg_name);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
if (lv->access & ACCESS_SNAPSHOT_ORG) {
log_error("can't remove logical volume %s under snapshot",
lv_name);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
if (lv->open) {
log_error("can't remove open %s logical volume %s",
lv->access & ACCESS_SNAPSHOT ? "snapshot" : "",
lv_name);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
if (!arg_count(force_ARG)) {
log_verbose("releasing logical volume %s", lv_name);
if (lv_remove(vg, lv)) {
log_error("Error releasing logical volume %s", lv_name);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
log_verbose("unlinking special file %s", lv_name);
/* store it on disks */
if (ios->vg_write(vg))
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
if ((ret = do_autobackup(vg_name, vg)))
return ret;
if (arg_count(allocation_ARG) == 0) {
log_error("Please give the x option");
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
ios = active_ios();
if (!(arg_count(all_ARG)) && !argc) {
log_error("Please give a physical volume path");
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
if (arg_count(all_ARG) && argc) {
log_error("Option a and PhysicalVolumePath are exclusive");
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
if (arg_count(all_ARG)) {
log_verbose("Scanning for physical volume names");
if (!(pvs_list = ios->get_pvs(ios))) {
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
list_for_each(pvh, &pvs_list->list) {
if (!argc) {
log_error("Please enter a physical volume path");
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
if (arg_count(yes_ARG) && !arg_count(force_ARG)) {
log_error("option y can only be given with option f");
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
for (opt = 0; opt < argc; opt++)
if (argc == 0) {
log_error("please enter a physical volume path");
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
if (arg_count(colon_ARG) && arg_count(verbose_ARG)) {
log_error("option v not allowed with option c");
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
for (opt = 0; opt < argc; opt++)
struct list_head *pvh;
struct physical_volume *pv;
- __uint64_t size_total = 0;
- __uint64_t size_new = 0;
- __uint64_t size = 0;
+ uint64_t size_total = 0;
+ uint64_t size_new = 0;
+ uint64_t size = 0;
int len = 0;
pv_max_name_len = 0;
if (arg_count(novolumegroup_ARG) && arg_count(exported_ARG)) {
log_error("options e and n incompatible");
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
if (arg_count(exported_ARG) || arg_count(novolumegroup_ARG))
ios = active_ios();
if (!(pvs_list = ios->get_pvs(ios)))
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
/* eliminate exported/new if required */
list_for_each(pvh, &pvs_list->list) {
{
char *lvm_autobackup;
- if (arg_count(autobackup_ARG))
+ if (arg_count(autobackup_ARG)) {
_autobackup = strcmp(arg_str_value(autobackup_ARG, "y"), "n");
- else {
- _autobackup = 1; /* default */
+ return 0;
+ }
+
+ _autobackup = 1; /* default */
+
+ lvm_autobackup = getenv("LVM_AUTOBACKUP");
+ if (!lvm_autobackup)
+ return 0;
- lvm_autobackup = getenv("LVM_AUTOBACKUP");
- if (lvm_autobackup) {
- log_print
- ("using environment variable LVM_AUTOBACKUP to set option A");
- if (strcasecmp(lvm_autobackup, "no") == 0)
- _autobackup = 0;
- else if (strcasecmp(lvm_autobackup, "yes") != 0) {
- log_error
- ("environment variable LVM_AUTOBACKUP has invalid value \"%s\"!",
- lvm_autobackup);
- return -1;
- }
- }
+ log_print("using environment variable LVM_AUTOBACKUP "
+ "to set option A");
+ if (!strcasecmp(lvm_autobackup, "no"))
+ _autobackup = 0;
+ else if (strcasecmp(lvm_autobackup, "yes")) {
+ log_error("environment variable LVM_AUTOBACKUP has "
+ "invalid value \"%s\"!", lvm_autobackup);
+ return -1;
}
return 0;
SIZE_SHORT),
display_size(sectors_to_k(LVM_MAX_PE_SIZE),
SIZE_SHORT));
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
}
if (argc == 0) {
log_error
("please enter a volume group name and physical volumes");
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
vg_name = argv[0];
if (argc == 1) {
log_error("please enter physical volume name(s)");
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
if ((vg = ios->vg_read(ios, vg_name))) {
log_error
("Volume group already exists: please use a different name");
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
/***** FIXME: confirm we're now free of this restriction
*****/
if (!(vg = vg_create())) {
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
/* read all PVs */
if (!(pv_dev = dev_cache_get(pv_name))) {
log_error("Device %s not found", pv_name);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
if (!(pv = ios->pv_read(ios, pv_dev))) {
log_error("Physical volume %s not found", pv_name);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
log_verbose("checking physical volume %s", pv_name);
/* FIXME size should already be filled in pv structure?! */
if ((size = dev_get_size(pv_dev)) < 0) {
log_error("Unable to get size of %s", pv_name);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
log_verbose("physical volume %s is %d 512-byte sectors",
log_error
("physical volume %s occurs multiple times",
pv_name);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
}
if ((pvp = dbg_realloc(pvp, (np + 2) * sizeof (pv *))) == NULL) {
log_error("realloc error in file \"%s\" [line %d]",
__FILE__, __LINE__);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
pvp[np] = pv;
if (np == 0) {
log_error("no valid physical volumes in command line");
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
if (np != count_sav) {
log_error("some invalid physical volumes in command line");
- return LVM_ECMD_FAILED; /* Impossible to reach here? */
+ return ECMD_FAILED; /* Impossible to reach here? */
}
log_verbose("%d physical volume%s will be inserted into "
log_verbose("maximum of %d physical volumes", max_pv);
if (max_pv < 0 || max_pv <= np || max_pv > MAX_PV) {
log_error("invalid maximum physical volumes -p %d", max_pv);
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
vg->max_pv = max_pv;
log_verbose("maximum of %d logical volumes", max_lv);
if (max_lv < 0 || max_lv > MAX_LV) {
log_error("invalid maximum logical volumes -l %d", max_lv);
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
vg->max_lv = max_lv;
LVM_PE_T_MAX, SHORT)));
dbg_free(dummy);
}
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
if (arg_count(physicalextentsize_ARG) == 0) {
/* store vg on disk(s) */
if (ios->vg_write(ios, vg)) {
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
log_verbose("creating volume group directory %s%s", prefix, vg_name);
if (vg_create_dir_and_group(&vg)) {
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
/* FIXME Activate it */
if (argc != 2) {
log_error("command line too short");
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
ios = active_ios();
if (strlen(vg_name_new = argv[1]) > NAME_LEN - length - 2) {
log_error("New logical volume path exceeds maximum length "
"of %d!", NAME_LEN - length - 2);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
if (vg_check_name(vg_name_new) < 0) {
- return LVM_EINVALID_CMD_LINE;
+ return EINVALID_CMD_LINE;
}
/* FIXME Handle prefix-related logic internally within ios functions? */
if (strcmp(vg_name_old, vg_name_new) == 0) {
log_error("volume group names must be different");
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
log_verbose("Checking existing volume group %s", vg_name_old);
if (!(vg_old = ios->vg_read(ios, vg_name_old))) {
log_error("volume group %s doesn't exist", vg_name_old);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
if (vg_old->status & STATUS_ACTIVE) {
log_error("Volume group %s still active", vg_name_old);
log_verbose("Checking new volume group %s", vg_name_new);
if ((vg_new = ios->vg_read(ios, vg_name_new))) {
log_error("New volume group %s already exists", vg_name_new);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
/* change the volume name in all structures */
lv_change_vgname(vg_name_new, vg_old->lv[l]->name))) {
log_error("A new logical volume path exceeds "
"maximum of %d!", NAME_LEN - 2);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
strcpy(vg_old->lv[l]->name, lv_name_ptr);
}
if (vg_remove_dir_and_group_and_nodes(vg_name_old) < 0) {
log_error("removing volume group nodes and directory of \"%s\"",
vg_name_old);
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
/* store it on disks */
log_verbose("updating volume group name");
if (ios->vg_write(ios, vg_old)) {
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
log_verbose("creating volume group directory %s%s", prefix,
vg_name_new);
if (vg_create_dir_and_group_and_nodes(vg_old)) {
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
}
if ((ret = do_autobackup(vg_name_new, vg_old)))
- return LVM_ECMD_FAILED;
+ return ECMD_FAILED;
log_print("Volume group %s successfully renamed to %s",
vg_name_old, vg_name_new);