/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2016 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2017 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
#include "memlock.h"
+/*
+ * Passed back from callee to request caller to
+ * commit / update and reload / backup metadata.
+ *
+ * This allows for one metadata update per command run
+ * (unless mandatory interim ones in callee).
+ */
+enum metadata_request {
+ MR_COMMIT = 0x1,
+ MR_UPDATE_RELOAD = 0x2,
+ MR_BACKUP = 0x4
+};
+
+static int _vg_write_commit(const struct logical_volume *lv, const char *what)
+{
+ log_very_verbose("Updating %slogical volume %s on disk(s).",
+ what ? : "", display_lvname(lv));
+ if (!vg_write(lv->vg) || !vg_commit(lv->vg)) {
+ log_error("Failed to update %smetadata of %s on disk.",
+ what ? : "", display_lvname(lv));
+ return 0;
+ }
+
+ return 1;
+}
+
static int _lvchange_permission(struct cmd_context *cmd,
- struct logical_volume *lv)
+ struct logical_volume *lv,
+ enum metadata_request *mr)
{
uint32_t lv_access;
struct lvinfo info;
display_lvname(lv));
}
- if (!lv_update_and_reload(lv))
- return_0;
+ /* Request caller to update and reload metadata */
+ *mr |= MR_UPDATE_RELOAD;
return 1;
}
static int _lvchange_pool_update(struct cmd_context *cmd,
- struct logical_volume *lv)
+ struct logical_volume *lv,
+ enum metadata_request *mr)
{
int update = 0;
unsigned val;
if (!update)
return 0;
- if (!lv_update_and_reload(lv))
- return_0;
-
+ *mr |= MR_UPDATE_RELOAD;
return 1;
}
if (!seg_is_raid(seg) && !seg->log_lv) {
if (lv_is_not_synced(lv)) {
lv->status &= ~LV_NOTSYNCED;
- log_very_verbose("Updating logical volume %s on disk(s).",
- display_lvname(lv));
- if (!vg_write(lv->vg) || !vg_commit(lv->vg)) {
- log_error("Failed to update metadata on disk.");
+ if (!_vg_write_commit(lv, NULL))
return 0;
- }
}
if (!_reactivate_lv(lv, active, exclusive)) {
return 0;
}
- if (!vg_write(lv->vg) || !vg_commit(lv->vg)) {
- log_error("Failed to update intermediate VG metadata on disk.");
+ if (!_vg_write_commit(lv, "intermediate")) {
if (!_reactivate_lv(lv, active, exclusive))
stack;
return 0;
return 0;
}
- if (!vg_write(lv->vg) || !vg_commit(lv->vg)) {
- log_error("Failed to update metadata on disk for %s.",
- display_lvname(lv));
+ if (!_vg_write_commit(lv, NULL))
return 0;
- }
if (!_reactivate_lv(lv, active, exclusive)) {
backup(lv->vg);
return 1;
}
-static int _lvchange_alloc(struct cmd_context *cmd, struct logical_volume *lv)
+static int _lvchange_alloc(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ enum metadata_request *mr)
{
int want_contiguous = arg_int_value(cmd, contiguous_ARG, 0);
alloc_policy_t alloc = (alloc_policy_t)
log_very_verbose("Updating logical volume %s on disk(s).", display_lvname(lv));
/* No need to suspend LV for this change */
- if (!vg_write(lv->vg) || !vg_commit(lv->vg))
- return_0;
- backup(lv->vg);
+ /* Request caller to commit+backuo metadata */
+ *mr |= (MR_COMMIT | MR_BACKUP);
return 1;
}
static int _lvchange_errorwhenfull(struct cmd_context *cmd,
- struct logical_volume *lv)
+ struct logical_volume *lv,
+ enum metadata_request *mr)
{
unsigned ewf = arg_int_value(cmd, errorwhenfull_ARG, 0);
else
lv->status &= ~LV_ERROR_WHEN_FULL;
- if (!lv_update_and_reload(lv))
- return_0;
+ /* Request caller to update and reload metadata */
+ *mr |= MR_UPDATE_RELOAD;
return 1;
}
static int _lvchange_readahead(struct cmd_context *cmd,
- struct logical_volume *lv)
+ struct logical_volume *lv,
+ enum metadata_request *mr)
{
unsigned read_ahead = 0;
unsigned pagesize = (unsigned) lvm_getpagesize() >> SECTOR_SHIFT;
log_verbose("Setting read ahead to %u for %s.",
read_ahead, display_lvname(lv));
- if (!lv_update_and_reload(lv))
- return_0;
+ /* Request caller to update and reload metadata */
+ *mr |= MR_UPDATE_RELOAD;
return 1;
}
static int _lvchange_persistent(struct cmd_context *cmd,
- struct logical_volume *lv)
+ struct logical_volume *lv,
+ enum metadata_request *mr)
{
enum activation_change activate = CHANGE_AN;
lv->major, lv->minor, display_lvname(lv));
}
- log_very_verbose("Updating logical volume %s on disk(s).",
- display_lvname(lv));
-
- if (!vg_write(lv->vg) || !vg_commit(lv->vg))
- return_0;
+ if (!_vg_write_commit(lv, NULL))
+ return 0;
if (activate != CHANGE_AN) {
log_verbose("Re-activating logical volume %s.", display_lvname(lv));
}
}
- backup(lv->vg);
+ /* Request caller to backup metadata */
+ *mr |= MR_BACKUP;
return 1;
}
-static int _lvchange_cache(struct cmd_context *cmd, struct logical_volume *lv)
+static int _lvchange_cache(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ enum metadata_request *mr)
{
cache_metadata_format_t format;
cache_mode_t mode;
!cache_set_policy(first_seg(lv), name, settings))
goto_out;
- if (!lv_update_and_reload(lv))
- goto_out;
+ /* Request caller to update and reload metadata */
+ *mr |= MR_UPDATE_RELOAD;
r = 1;
out:
return r;
}
-static int _lvchange_tag(struct cmd_context *cmd, struct logical_volume *lv, int arg)
+static int _lvchange_tag(struct cmd_context *cmd, struct logical_volume *lv,
+ int arg, enum metadata_request *mr)
{
if (!change_tag(cmd, NULL, lv, NULL, arg))
return_0;
log_very_verbose("Updating logical volume %s on disk(s).", display_lvname(lv));
/* No need to suspend LV for this change */
- if (!vg_write(lv->vg) || !vg_commit(lv->vg))
- return_0;
-
- backup(lv->vg);
+ /* Request caller to commit+backup metadata */
+ *mr |= (MR_COMMIT | MR_BACKUP);
return 1;
}
return lv_raid_rebuild(lv, rebuild_pvh);
}
-static int _lvchange_writemostly(struct logical_volume *lv)
+static int _lvchange_writemostly(struct logical_volume *lv,
+ enum metadata_request *mr)
{
int pv_count, i = 0;
uint32_t s, writemostly;
}
}
- if (!lv_update_and_reload(lv))
- return_0;
+ /* Request caller to update and reload metadata */
+ *mr |= MR_UPDATE_RELOAD;
return 1;
}
-static int _lvchange_recovery_rate(struct logical_volume *lv)
+static int _lvchange_recovery_rate(struct logical_volume *lv,
+ enum metadata_request *mr)
{
struct cmd_context *cmd = lv->vg->cmd;
struct lv_segment *raid_seg = first_seg(lv);
return 0;
}
- if (!lv_update_and_reload(lv))
- return_0;
+ /* Request caller to update and reload metadata */
+ *mr |= MR_UPDATE_RELOAD;
return 1;
}
-static int _lvchange_profile(struct logical_volume *lv)
+static int _lvchange_profile(struct logical_volume *lv,
+ enum metadata_request *mr)
{
const char *old_profile_name, *new_profile_name;
struct profile *new_profile;
log_verbose("Changing configuration profile for LV %s: %s -> %s.",
display_lvname(lv), old_profile_name, new_profile_name);
- if (!vg_write(lv->vg) || !vg_commit(lv->vg))
- return_0;
-
- backup(lv->vg);
+ /* Request caller to commit+backup metadata */
+ *mr |= (MR_COMMIT | MR_BACKUP);
return 1;
}
-static int _lvchange_activation_skip(struct logical_volume *lv)
+static int _lvchange_activation_skip(struct logical_volume *lv, enum metadata_request *mr)
{
int skip = arg_int_value(lv->vg->cmd, setactivationskip_ARG, 0);
log_verbose("Changing activation skip flag to %s for LV %s.",
display_lvname(lv), skip ? "enabled" : "disabled");
- if (!vg_write(lv->vg) || !vg_commit(lv->vg))
- return_0;
+ /* Request caller to commit+backup metadata */
+ *mr |= (MR_COMMIT | MR_BACKUP);
- backup(lv->vg);
+ return 1;
+}
+
+/* Update and reload or commit and/or backup metadata for @lv as requested by @mr */
+static int _commit_update_backup(struct logical_volume *lv,
+ const enum metadata_request mr)
+{
+ if (mr & MR_UPDATE_RELOAD) {
+ if (!lv_update_and_reload(lv))
+ return_0;
+
+ } else if ((mr & MR_COMMIT) &&
+ !_vg_write_commit(lv, NULL))
+ return 0;
+
+ if (mr & MR_BACKUP)
+ backup(lv->vg);
return 1;
}
{
int doit = 0, docmds = 0;
int i, opt_enum;
+ enum metadata_request mr = 0;
/*
* If a persistent lv lock already exists from activation
if (!arg_is_set(cmd, opt_enum))
continue;
+ /* Archive will only happen once per run */
if (!archive(lv->vg))
return_ECMD_FAILED;
switch (opt_enum) {
case permission_ARG:
- doit += _lvchange_permission(cmd, lv);
+ doit += _lvchange_permission(cmd, lv, &mr);
break;
case alloc_ARG:
case contiguous_ARG:
- doit += _lvchange_alloc(cmd, lv);
+ doit += _lvchange_alloc(cmd, lv, &mr);
break;
case errorwhenfull_ARG:
- doit += _lvchange_errorwhenfull(cmd, lv);
+ doit += _lvchange_errorwhenfull(cmd, lv, &mr);
break;
case readahead_ARG:
- doit += _lvchange_readahead(cmd, lv);
+ doit += _lvchange_readahead(cmd, lv, &mr);
break;
case persistent_ARG:
- doit += _lvchange_persistent(cmd, lv);
+ doit += _lvchange_persistent(cmd, lv, &mr);
break;
case discards_ARG:
case zero_ARG:
- doit += _lvchange_pool_update(cmd, lv);
+ doit += _lvchange_pool_update(cmd, lv, &mr);
break;
case addtag_ARG:
case deltag_ARG:
- doit += _lvchange_tag(cmd, lv, opt_enum);
+ doit += _lvchange_tag(cmd, lv, opt_enum, &mr);
break;
case writemostly_ARG:
case writebehind_ARG:
- doit += _lvchange_writemostly(lv);
+ doit += _lvchange_writemostly(lv, &mr);
break;
case minrecoveryrate_ARG:
case maxrecoveryrate_ARG:
- doit += _lvchange_recovery_rate(lv);
+ doit += _lvchange_recovery_rate(lv, &mr);
break;
case profile_ARG:
case metadataprofile_ARG:
case detachprofile_ARG:
- doit += _lvchange_profile(lv);
+ doit += _lvchange_profile(lv, &mr);
break;
case setactivationskip_ARG:
- doit += _lvchange_activation_skip(lv);
+ doit += _lvchange_activation_skip(lv, &mr);
break;
case cachemode_ARG:
case cachepolicy_ARG:
case cachesettings_ARG:
- doit += _lvchange_cache(cmd, lv);
+ doit += _lvchange_cache(cmd, lv, &mr);
break;
default:
if (doit != docmds)
return_ECMD_FAILED;
+ if (!_commit_update_backup(lv, mr))
+ return_ECMD_FAILED;
+
return ECMD_PROCESSED;
}
struct logical_volume *lv,
struct processing_handle *handle)
{
- if (!_lvchange_persistent(cmd, lv))
+ enum metadata_request mr = 0;
+
+ if (!_lvchange_persistent(cmd, lv, &mr))
+ return_ECMD_FAILED;
+
+ if (!_commit_update_backup(lv, mr))
return_ECMD_FAILED;
return ECMD_PROCESSED;
cmd->command->command_index, cmd->command->command_id);
return ECMD_FAILED;
}
-