summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2015-03-02 15:45:55 -0600
committerDavid Teigland <teigland@redhat.com>2015-03-03 12:25:59 -0600
commitf4f819ea73f29880f17ad13958c115cbd3ee114f (patch)
tree5d5599c41660aaff367bced0c38490818f65b568
parent8df4b3a2527d171a4b94d2b090c822bc04fb4bc0 (diff)
downloadlvm2-dev-dct-lvmlockd-X.tar.gz
lvmlockd: special status for lockd VGs and LVsdev-dct-lvmlockd-X
Previous versions of lvm don't recognize lock_type in lockd VGs, so they would allow a lockd VG to be used as a local VG without restriction. So prevent this, the WRITE flag is removed from lockd VGs and replaced with the WRITE_LOCKD flag. This causes old versions of lvm to think the VG is not writable. Similarly, old versions need to be prevented from writing to LVs in lockd VGs (a read only VG does not prevent lvm from writing to LVs in it). So, LVs in lockd VGs have WRITE replaced by WRITE_LOCKD. In both cases, WRITE_LOCKD is put on the flags line of the metadata instead of the status line. If it was put on the status line, old versions of lvm would ignore the VG because of the unrecognized flag, and the PVs in the VG would appear unused. In memory, lvm continues to only use the WRITE flag with lv->status. WRITE is swapped with WRITE_LOCKD when the LV is read/written on disk. In memory, lvm uses both WRITE and WRITE_LOCKD with vg->status as appropriate. The hidden/internal lvmlock LV is given the special LV flag like other special lvs. This does not go to disk.
-rw-r--r--lib/format1/disk-rep.h3
-rw-r--r--lib/format1/import-export.c16
-rw-r--r--lib/format_text/export.c16
-rw-r--r--lib/format_text/flags.c4
-rw-r--r--lib/format_text/import_vsn1.c25
-rw-r--r--lib/locking/lvmlockd.c3
-rw-r--r--lib/metadata/lv_manip.c6
-rw-r--r--lib/metadata/metadata-exported.h7
-rw-r--r--lib/metadata/metadata.c27
-rw-r--r--lib/metadata/vg.c8
-rw-r--r--lib/misc/lvm-string.c3
-rw-r--r--lib/report/report.c4
-rw-r--r--tools/commands.h3
-rw-r--r--tools/lvchange.c2
-rw-r--r--tools/lvconvert.c2
-rw-r--r--tools/vgchange.c1
-rw-r--r--tools/vgconvert.c5
-rw-r--r--tools/vgreduce.c5
18 files changed, 110 insertions, 30 deletions
diff --git a/lib/format1/disk-rep.h b/lib/format1/disk-rep.h
index 94d27894f..8da77f635 100644
--- a/lib/format1/disk-rep.h
+++ b/lib/format1/disk-rep.h
@@ -41,7 +41,7 @@
#define VG_WRITE 0x02 /* " */
#define VG_CLUSTERED 0x04 /* " */
#define VG_SHARED 0x08 /* " */
-#define VG_LOCK_TYPE 0x10 /* " */
+#define VG_WRITE_LOCKD 0x10 /* " */
/* logical volume */
#define LV_ACTIVE 0x01 /* lv_status */
@@ -52,6 +52,7 @@
#define LV_WRITE 0x02 /* " */
#define LV_SNAPSHOT 0x04 /* " */
#define LV_SNAPSHOT_ORG 0x08 /* " */
+#define LV_WRITE_LOCKD 0x10 /* " */
#define LV_BADBLOCK_ON 0x01 /* lv_badblock */
diff --git a/lib/format1/import-export.c b/lib/format1/import-export.c
index 855c04273..f3c840450 100644
--- a/lib/format1/import-export.c
+++ b/lib/format1/import-export.c
@@ -243,8 +243,8 @@ int import_vg(struct dm_pool *mem,
if (vgd->vg_access & VG_CLUSTERED)
vg->status |= CLUSTERED;
- if (vgd->vg_access & VG_LOCK_TYPE)
- vg->status |= LOCK_TYPE;
+ if (vgd->vg_access & VG_WRITE_LOCKD)
+ vg->status |= LVM_WRITE_LOCKD;
if (vgd->vg_access & VG_SHARED)
vg->status |= SHARED;
@@ -273,8 +273,8 @@ int export_vg(struct vg_disk *vgd, struct volume_group *vg)
if (vg_is_clustered(vg))
vgd->vg_access |= VG_CLUSTERED;
- if (vg->status & LOCK_TYPE)
- vgd->vg_access |= VG_LOCK_TYPE;
+ if (vg->status & LVM_WRITE_LOCKD)
+ vgd->vg_access |= VG_WRITE_LOCKD;
if (vg->status & SHARED)
vgd->vg_access |= VG_SHARED;
@@ -324,6 +324,9 @@ int import_lv(struct cmd_context *cmd, struct dm_pool *mem,
if (lvd->lv_access & LV_WRITE)
lv->status |= LVM_WRITE;
+ if (lvd->lv_access & LV_WRITE_LOCKD)
+ lv->status |= LVM_WRITE;
+
if (lvd->lv_badblock)
lv->status |= BADBLOCK_ON;
@@ -356,9 +359,12 @@ static void _export_lv(struct lv_disk *lvd, struct volume_group *vg,
if (lv->status & LVM_READ)
lvd->lv_access |= LV_READ;
- if (lv->status & LVM_WRITE)
+ if ((lv->status & LVM_WRITE) && !(vg->status & LVM_WRITE_LOCKD))
lvd->lv_access |= LV_WRITE;
+ if ((lv->status & LVM_WRITE) && (vg->status & LVM_WRITE_LOCKD))
+ lvd->lv_access |= LV_WRITE_LOCKD;
+
if (lv->status & SPINDOWN_LV)
lvd->lv_status |= LV_SPINDOWN;
diff --git a/lib/format_text/export.c b/lib/format_text/export.c
index 3439f9218..63bd9ed75 100644
--- a/lib/format_text/export.c
+++ b/lib/format_text/export.c
@@ -614,9 +614,25 @@ static int _print_lv(struct formatter *f, struct logical_volume *lv)
outf(f, "id = \"%s\"", buffer);
+ /*
+ * A writable LV in a lockd VG is written to disk with WRITE_LOCKD
+ * replacing WRITE, so that pre-lockd lvm versions will not think the
+ * LV is writable. In memory, only the WRITE lv status flag is used.
+ */
+
+ if ((lv->status & LVM_WRITE) && (lv->vg->status & LVM_WRITE_LOCKD)) {
+ lv->status &= ~LVM_WRITE;
+ lv->status |= LVM_WRITE_LOCKD;
+ }
+
if (!_print_flag_config(f, lv->status, LV_FLAGS))
return_0;
+ if (lv->status & LVM_WRITE_LOCKD) {
+ lv->status |= LVM_WRITE;
+ lv->status &= ~LVM_WRITE_LOCKD;
+ }
+
if (!_out_tags(f, &lv->tags))
return_0;
diff --git a/lib/format_text/flags.c b/lib/format_text/flags.c
index a933013cf..dbef2839b 100644
--- a/lib/format_text/flags.c
+++ b/lib/format_text/flags.c
@@ -34,8 +34,8 @@ static const struct flag _vg_flags[] = {
{PVMOVE, "PVMOVE", STATUS_FLAG},
{LVM_READ, "READ", STATUS_FLAG},
{LVM_WRITE, "WRITE", STATUS_FLAG},
+ {LVM_WRITE_LOCKD, "WRITE_LOCKD", COMPATIBLE_FLAG},
{CLUSTERED, "CLUSTERED", STATUS_FLAG},
- {LOCK_TYPE, "LOCK_TYPE", STATUS_FLAG},
{SHARED, "SHARED", STATUS_FLAG},
{PARTIAL_VG, NULL, 0},
{PRECOMMITTED, NULL, 0},
@@ -54,6 +54,7 @@ static const struct flag _pv_flags[] = {
static const struct flag _lv_flags[] = {
{LVM_READ, "READ", STATUS_FLAG},
{LVM_WRITE, "WRITE", STATUS_FLAG},
+ {LVM_WRITE_LOCKD, "WRITE_LOCKD", COMPATIBLE_FLAG},
{FIXED_MINOR, "FIXED_MINOR", STATUS_FLAG},
{VISIBLE_LV, "VISIBLE", STATUS_FLAG},
{PVMOVE, "PVMOVE", STATUS_FLAG},
@@ -91,6 +92,7 @@ static const struct flag _lv_flags[] = {
{CACHE_POOL_DATA, NULL, 0},
{CACHE_POOL_METADATA, NULL, 0},
{LV_PENDING_DELETE, NULL, 0}, /* FIXME Display like COMPATIBLE_FLAG */
+ {LVMLOCK, NULL, 0},
{0, NULL, 0}
};
diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c
index 7fb4a5590..9993b150d 100644
--- a/lib/format_text/import_vsn1.c
+++ b/lib/format_text/import_vsn1.c
@@ -550,6 +550,28 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
return 0;
}
+ /*
+ * A lockd VG is represented both on disk and in memory with
+ * status WRITE_LOCKD. A non-lockd VG is represented on disk
+ * and in memory with status WRITE.
+ *
+ * An LV in a lockd VG is represented on disk with status WRITE_LOCKD,
+ * BUT in memory with status WRITE. So, when a lockd LV is written to
+ * disk, WRITE is changed to WRITE_LOCKD, and when a lockd LV is read
+ * from disk, WRITE_LOCKD is changed to WRITE.
+ *
+ * This is done to prevent pre-lockd versions of lvm from being able
+ * to write to lockd LVs. Old versions of lvm will not see WRITE on
+ * disk for the LV, and think the LV is read only, and the old version
+ * will not look for the WRITE_LOCKD flag. New versions of lvm will
+ * recognize either the WRITE or WRITE_LOCKD flag.
+ */
+
+ if (lv->status & LVM_WRITE_LOCKD) {
+ lv->status &= ~LVM_WRITE_LOCKD;
+ lv->status |= LVM_WRITE;
+ }
+
if (dm_config_has_node(lvn, "creation_time")) {
if (!_read_uint64(lvn, "creation_time", &timestamp)) {
log_error("Invalid creation_time for logical volume %s.",
@@ -642,6 +664,9 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
vg->pool_metadata_spare_lv = lv;
}
+ if (!lv_is_visible(lv) && !strcmp(lv->name, "lvmlock"))
+ lv->status |= LVMLOCK;
+
return 1;
}
diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c
index d11725575..15af3a796 100644
--- a/lib/locking/lvmlockd.c
+++ b/lib/locking/lvmlockd.c
@@ -371,7 +371,8 @@ static int _create_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg,
return 0;
}
- lv_set_hidden(lv);
+ lv_set_hidden(lv); /* FIXME: should this be done before vg is written? */
+ lv->status |= LVMLOCK; /* flag not written to metadata */
return 1;
}
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 485c55d92..5546421f5 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -4442,9 +4442,7 @@ static int _lvresize_check_lv(struct cmd_context *cmd, struct logical_volume *lv
return 0;
}
- /* FIXME: use a status flag instead of the name "lvmlock". */
-
- if (!lv_is_visible(lv) && !lv_is_thin_pool_metadata(lv) && strcmp(lv->name, "lvmlock")) {
+ if (!lv_is_visible(lv) && !lv_is_thin_pool_metadata(lv) && !lv_is_lvmlock(lv)) {
log_error("Can't resize internal logical volume %s", lv->name);
return 0;
}
@@ -5466,7 +5464,7 @@ int lv_remove_single(struct cmd_context *cmd, struct logical_volume *lv,
vg = lv->vg;
- if (!vg_check_status(vg, LVM_WRITE))
+ if (!vg_status_writable(vg))
return_0;
if (lv_is_origin(lv)) {
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index d544ed8bc..ed3967dcf 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -61,7 +61,6 @@
#define CLUSTERED UINT64_C(0x0000000000000400) /* VG */
//#define SHARED UINT64_C(0x0000000000000800) /* VG */
-#define LOCK_TYPE UINT64_C(0x0000000000001000) /* VG */
/* FIXME Remove when metadata restructuring is completed */
#define SNAPSHOT UINT64_C(0x0000000000001000) /* LV - internal use only */
@@ -123,7 +122,9 @@
#define PV_ALLOCATION_PROHIBITED UINT64_C(0x0010000000000000) /* PV - internal use only - allocation prohibited
e.g. to prohibit allocation of a RAID image
on a PV already holing an image of the RAID set */
-/* Next unused flag: UINT64_C(0x0020000000000000) */
+#define LVMLOCK UINT64_C(0x0020000000000000) /* LV - Internal use only */
+#define LVM_WRITE_LOCKD UINT64_C(0x0040000000000000) /* LV, VG */
+/* Next unused flag: UINT64_C(0x0080000000000000) */
/* Format features flags */
#define FMT_SEGMENTS 0x00000001U /* Arbitrary segment params? */
@@ -219,6 +220,7 @@
#define lv_is_pool_data(lv) (((lv)->status & (CACHE_POOL_DATA | THIN_POOL_DATA)) ? 1 : 0)
#define lv_is_pool_metadata(lv) (((lv)->status & (CACHE_POOL_METADATA | THIN_POOL_METADATA)) ? 1 : 0)
#define lv_is_pool_metadata_spare(lv) (((lv)->status & POOL_METADATA_SPARE) ? 1 : 0)
+#define lv_is_lvmlock(lv) (((lv)->status & LVMLOCK) ? 1 : 0)
#define lv_is_rlog(lv) (((lv)->status & REPLICATOR_LOG) ? 1 : 0)
@@ -1010,6 +1012,7 @@ int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow,
int vg_remove_snapshot(struct logical_volume *cow);
int vg_check_status(const struct volume_group *vg, uint64_t status);
+int vg_status_writable(const struct volume_group *vg);
int vg_check_pv_dev_block_sizes(const struct volume_group *vg);
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index a2208a355..8b540ba50 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -1047,6 +1047,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name)
goto bad;
}
+ /* vg_set_lock_type() may clear LVM_WRITE and set LVM_WRITE_LOCKD */
vg->status = (RESIZEABLE_VG | LVM_READ | LVM_WRITE);
vg->system_id = NULL;
if (!(vg->lvm1_system_id = dm_pool_zalloc(vg->vgmem, NAME_LEN + 1)))
@@ -4288,8 +4289,8 @@ static uint32_t _vg_bad_status_bits(const struct volume_group *vg,
failure |= FAILED_EXPORTED;
}
- if ((status & LVM_WRITE) &&
- !(vg->status & LVM_WRITE)) {
+ if ((status & (LVM_WRITE | LVM_WRITE_LOCKD)) &&
+ (!(vg->status & (LVM_WRITE | LVM_WRITE_LOCKD)))) {
log_error("Volume group %s is read-only", vg->name);
failure |= FAILED_READ_ONLY;
}
@@ -4314,6 +4315,22 @@ int vg_check_status(const struct volume_group *vg, uint64_t status)
}
/*
+ * Return 1 if writeable.
+ * Return 0 if not writeable.
+ *
+ * The VG or LV is writable if either LVM_WRITE or LVM_WRITE_LOCKD are set.
+ */
+
+int vg_status_writable(const struct volume_group *vg)
+{
+ if (vg->status & LVM_WRITE)
+ return 1;
+ if (vg->status & LVM_WRITE_LOCKD)
+ return 1;
+ return 0;
+}
+
+/*
* VG is left unlocked on failure
*/
static struct volume_group *_recover_vg(struct cmd_context *cmd,
@@ -4542,8 +4559,10 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
return _vg_make_handle(cmd, vg, FAILED_LOCKING);
}
- if (is_orphan_vg(vg_name))
+ if (is_orphan_vg(vg_name)) {
status_flags &= ~LVM_WRITE;
+ status_flags &= ~LVM_WRITE_LOCKD;
+ }
consistent_in = consistent;
@@ -4644,7 +4663,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
uint32_t lock_flags = LCK_VG_READ;
if (flags & READ_FOR_UPDATE) {
- status |= EXPORTED_VG | LVM_WRITE;
+ status |= EXPORTED_VG | LVM_WRITE | LVM_WRITE_LOCKD;
lock_flags = LCK_VG_WRITE;
}
diff --git a/lib/metadata/vg.c b/lib/metadata/vg.c
index d50a88ebc..a23b4b6b9 100644
--- a/lib/metadata/vg.c
+++ b/lib/metadata/vg.c
@@ -635,8 +635,10 @@ int vg_set_lock_type(struct volume_group *vg, const char *lock_type)
return 0;
}
- if (is_lockd_type(lock_type))
- vg->status |= LOCK_TYPE;
+ if (is_lockd_type(lock_type)) {
+ vg->status |= LVM_WRITE_LOCKD;
+ vg->status &= ~LVM_WRITE;
+ }
return 1;
}
@@ -650,7 +652,7 @@ char *vg_attr_dup(struct dm_pool *mem, const struct volume_group *vg)
return NULL;
}
- repstr[0] = (vg->status & LVM_WRITE) ? 'w' : 'r';
+ repstr[0] = ((vg->status & LVM_WRITE) || (vg->status & LVM_WRITE_LOCKD)) ? 'w' : 'r';
repstr[1] = (vg_is_resizeable(vg)) ? 'z' : '-';
repstr[2] = (vg_is_exported(vg)) ? 'x' : '-';
repstr[3] = (vg_missing_pv_count(vg)) ? 'p' : '-';
diff --git a/lib/misc/lvm-string.c b/lib/misc/lvm-string.c
index 5d6385817..163fb67e5 100644
--- a/lib/misc/lvm-string.c
+++ b/lib/misc/lvm-string.c
@@ -162,7 +162,8 @@ static const char *_lvname_has_reserved_string(const char *lvname)
"_rmeta",
"_tdata",
"_tmeta",
- "_vorigin"
+ "_vorigin",
+ "lvmlock"
};
unsigned i;
diff --git a/lib/report/report.c b/lib/report/report.c
index b5418e55b..6dce65b83 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -1424,8 +1424,8 @@ static int _vgpermissions_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
- const char *perms = ((const struct volume_group *) data)->status & LVM_WRITE ? GET_FIRST_RESERVED_NAME(vg_permissions_rw)
- : GET_FIRST_RESERVED_NAME(vg_permissions_r);
+ const char *perms = ((const struct volume_group *) data)->status & (LVM_WRITE | LVM_WRITE_LOCKD) ? GET_FIRST_RESERVED_NAME(vg_permissions_rw)
+ : GET_FIRST_RESERVED_NAME(vg_permissions_r);
return _string_disp(rh, mem, field, &perms, private);
}
diff --git a/tools/commands.h b/tools/commands.h
index 08d4b4eee..0894284d3 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -988,7 +988,8 @@ xx(vgchange,
metadataprofile_ARG, monitor_ARG, noudevsync_ARG, metadatacopies_ARG,
vgmetadatacopies_ARG, partial_ARG, physicalextentsize_ARG, poll_ARG,
refresh_ARG, resizeable_ARG, resizable_ARG, select_ARG, sysinit_ARG,
- systemid_ARG, test_ARG, uuid_ARG, lockstart_ARG, lockstop_ARG, locktype_ARG, lockopt_ARG)
+ systemid_ARG, test_ARG, uuid_ARG, lockstart_ARG, lockstop_ARG, locktype_ARG, lockopt_ARG,
+ force_ARG)
xx(vgck,
"Check the consistency of volume group(s)",
diff --git a/tools/lvchange.c b/tools/lvchange.c
index 203af364c..b97190493 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -885,7 +885,7 @@ static int _lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
struct logical_volume *origin;
char snaps_msg[128];
- if (!(lv->vg->status & LVM_WRITE) &&
+ if (!vg_status_writable(lv->vg) &&
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG) ||
arg_count(cmd, discards_ARG) || arg_count(cmd, zero_ARG) ||
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 6ef0fe1f3..ec40852db 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -2003,7 +2003,7 @@ static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volu
return 0;
}
- if (!vg_check_status(vg, LVM_WRITE))
+ if (!vg_status_writable(vg))
return_0;
if (lv_is_pvmove(cow) || lv_is_mirror_type(cow) || lv_is_raid_type(cow) || lv_is_thin_type(cow)) {
diff --git a/tools/vgchange.c b/tools/vgchange.c
index a35c32ea0..3228ec4e5 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -538,7 +538,6 @@ static int _vgchange_locktype(struct cmd_context *cmd,
}
vg->status &= ~CLUSTERED;
- vg->status &= ~LOCK_TYPE;
vg->lock_type = "none";
vg->lock_args = NULL;
diff --git a/tools/vgconvert.c b/tools/vgconvert.c
index 50b3e44a9..b7b1f8e96 100644
--- a/tools/vgconvert.c
+++ b/tools/vgconvert.c
@@ -30,7 +30,10 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
struct lvinfo info;
int active = 0;
- if (!vg_check_status(vg, LVM_WRITE | EXPORTED_VG))
+ if (!vg_status_writable(vg))
+ return_ECMD_FAILED;
+
+ if (!vg_check_status(vg, EXPORTED_VG))
return_ECMD_FAILED;
if (vg->fid->fmt == cmd->fmt) {
diff --git a/tools/vgreduce.c b/tools/vgreduce.c
index fda8fb6d1..f634c604c 100644
--- a/tools/vgreduce.c
+++ b/tools/vgreduce.c
@@ -127,7 +127,10 @@ static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
{
int r;
- if (!vg_check_status(vg, EXPORTED_VG | LVM_WRITE | RESIZEABLE_VG))
+ if (!vg_status_writable(vg))
+ return_ECMD_FAILED;
+
+ if (!vg_check_status(vg, EXPORTED_VG | RESIZEABLE_VG))
return ECMD_FAILED;
r = vgreduce_single(cmd, vg, pv, 1);