mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-03 05:18:29 +03:00
pvscan: use process_each_vg for autoactivate
This refactors the code for autoactivation. Previously, as each PV was found, it would be sent to lvmetad, and the VG would be autoactivated using a non-standard VG processing function (the "activation_handler") called via a function pointer from within the lvmetad notification path. Now, any scanning that the command needs to do (scanning only the named device args, or scanning all devices when there are no args), is done first, before any activation is attempted. During the scans, the VG names are saved. After scanning is complete, process_each_vg is used to do autoactivation of the saved VG names. This makes pvscan activation much more similar to activation done with vgchange or lvchange. The separate autoactivate phase also means that if lvmetad is disabled (either before or during the scan), the command can continue with the activation step by simply not using lvmetad and reverting to disk scanning to do the activation.
This commit is contained in:
parent
55683a659f
commit
9b640c3684
162
lib/cache/lvmetad.c
vendored
162
lib/cache/lvmetad.c
vendored
@ -23,6 +23,7 @@
|
|||||||
#include "crc.h"
|
#include "crc.h"
|
||||||
#include "lvm-signal.h"
|
#include "lvm-signal.h"
|
||||||
#include "lvmlockd.h"
|
#include "lvmlockd.h"
|
||||||
|
#include "str_list.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
@ -399,9 +400,6 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler,
|
|
||||||
int ignore_obsolete, int do_wait);
|
|
||||||
|
|
||||||
static daemon_reply _lvmetad_send(struct cmd_context *cmd, const char *id, ...)
|
static daemon_reply _lvmetad_send(struct cmd_context *cmd, const char *id, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@ -1017,9 +1015,9 @@ int lvmetad_vg_update(struct volume_group *vg)
|
|||||||
|
|
||||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||||
/* NB. the PV fmt pointer is sometimes wrong during vgconvert */
|
/* NB. the PV fmt pointer is sometimes wrong during vgconvert */
|
||||||
if (pvl->pv->dev && !lvmetad_pv_found(&pvl->pv->id, pvl->pv->dev,
|
if (pvl->pv->dev && !lvmetad_pv_found(vg->cmd, &pvl->pv->id, pvl->pv->dev,
|
||||||
vg->fid ? vg->fid->fmt : pvl->pv->fmt,
|
vg->fid ? vg->fid->fmt : pvl->pv->fmt,
|
||||||
pvl->pv->label_sector, NULL, NULL))
|
pvl->pv->label_sector, NULL, NULL, NULL))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1303,14 +1301,16 @@ static int _extract_mdas(struct lvmcache_info *info, struct dm_config_tree *cft,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lvmetad_pv_found(const struct id *pvid, struct device *dev, const struct format_type *fmt,
|
int lvmetad_pv_found(struct cmd_context *cmd, const struct id *pvid, struct device *dev, const struct format_type *fmt,
|
||||||
uint64_t label_sector, struct volume_group *vg, activation_handler handler)
|
uint64_t label_sector, struct volume_group *vg,
|
||||||
|
struct dm_list *found_vgnames,
|
||||||
|
struct dm_list *changed_vgnames)
|
||||||
{
|
{
|
||||||
char uuid[64];
|
char uuid[64];
|
||||||
daemon_reply reply;
|
daemon_reply reply;
|
||||||
struct lvmcache_info *info;
|
struct lvmcache_info *info;
|
||||||
struct dm_config_tree *pvmeta, *vgmeta;
|
struct dm_config_tree *pvmeta, *vgmeta;
|
||||||
const char *status, *vgname, *vgid;
|
const char *status, *vgname;
|
||||||
int64_t changed;
|
int64_t changed;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
@ -1358,7 +1358,7 @@ int lvmetad_pv_found(const struct id *pvid, struct device *dev, const struct for
|
|||||||
}
|
}
|
||||||
|
|
||||||
log_debug_lvmetad("Telling lvmetad to store PV %s (%s) in VG %s", dev_name(dev), uuid, vg->name);
|
log_debug_lvmetad("Telling lvmetad to store PV %s (%s) in VG %s", dev_name(dev), uuid, vg->name);
|
||||||
reply = _lvmetad_send(vg->cmd, "pv_found",
|
reply = _lvmetad_send(cmd, "pv_found",
|
||||||
"pvmeta = %t", pvmeta,
|
"pvmeta = %t", pvmeta,
|
||||||
"vgname = %s", vg->name,
|
"vgname = %s", vg->name,
|
||||||
"metadata = %t", vgmeta,
|
"metadata = %t", vgmeta,
|
||||||
@ -1382,65 +1382,41 @@ int lvmetad_pv_found(const struct id *pvid, struct device *dev, const struct for
|
|||||||
daemon_reply_int(reply, "seqno_after", -1) != daemon_reply_int(reply, "seqno_before", -1)))
|
daemon_reply_int(reply, "seqno_after", -1) != daemon_reply_int(reply, "seqno_before", -1)))
|
||||||
log_warn("WARNING: Inconsistent metadata found for VG %s", vg->name);
|
log_warn("WARNING: Inconsistent metadata found for VG %s", vg->name);
|
||||||
|
|
||||||
/*
|
if (result && found_vgnames) {
|
||||||
* pvscan --cache does not perform any lvmlockd locking, and
|
status = daemon_reply_str(reply, "status", NULL);
|
||||||
* pvscan --cache -aay skips autoactivation in lockd VGs.
|
vgname = daemon_reply_str(reply, "vgname", NULL);
|
||||||
*
|
changed = daemon_reply_int(reply, "changed", 0);
|
||||||
* pvscan --cache populates lvmetad with VG metadata from disk.
|
|
||||||
* No lvmlockd locking is needed. It is expected that lockd VG
|
|
||||||
* metadata that is read by pvscan and populated in lvmetad may
|
|
||||||
* be immediately stale due to changes to the VG from other hosts
|
|
||||||
* during or after this pvscan. This is normal and not a problem.
|
|
||||||
* When a subsequent lvm command uses the VG, it will lock the VG
|
|
||||||
* with lvmlockd, read the VG from lvmetad, and update the cached
|
|
||||||
* copy from disk if necessary.
|
|
||||||
*
|
|
||||||
* pvscan --cache -aay does not activate LVs in lockd VGs because
|
|
||||||
* activation requires locking, and a lock-start operation is needed
|
|
||||||
* on a lockd VG before any locking can be performed in it.
|
|
||||||
*
|
|
||||||
* An equivalent of pvscan --cache -aay for lockd VGs is:
|
|
||||||
* 1. pvscan --cache
|
|
||||||
* 2. vgchange --lock-start
|
|
||||||
* 3. vgchange -aay -S 'locktype=sanlock || locktype=dlm'
|
|
||||||
*
|
|
||||||
* [We could eventually add support for autoactivating lockd VGs
|
|
||||||
* using pvscan by incorporating the lock start step (which can
|
|
||||||
* take a long time), but there may be a better option than
|
|
||||||
* continuing to overload pvscan.]
|
|
||||||
*
|
|
||||||
* Stages of starting a lockd VG:
|
|
||||||
*
|
|
||||||
* . pvscan --cache populates lockd VGs in lvmetad without locks,
|
|
||||||
* and this initial cached copy may quickly become stale.
|
|
||||||
*
|
|
||||||
* . vgchange --lock-start VG reads the VG without the VG lock
|
|
||||||
* because no locks are available until the locking is started.
|
|
||||||
* It only uses the VG name and lock_type from the VG metadata,
|
|
||||||
* and then only uses it to start the VG lockspace in lvmlockd.
|
|
||||||
*
|
|
||||||
* . Further lvm commands, e.g. activation, can then lock the VG
|
|
||||||
* with lvmlockd and use current VG metdata.
|
|
||||||
*/
|
|
||||||
if (handler && vg && is_lockd_type(vg->lock_type)) {
|
|
||||||
log_debug_lvmetad("Skip pvscan activation for lockd type VG %s", vg->name);
|
|
||||||
handler = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result && handler) {
|
/*
|
||||||
status = daemon_reply_str(reply, "status", "<missing>");
|
* If lvmetad now sees all PVs in the VG, it returned the
|
||||||
vgname = daemon_reply_str(reply, "vgname", "<missing>");
|
* "complete" status string. Add this VG name to the list
|
||||||
vgid = daemon_reply_str(reply, "vgid", "<missing>");
|
* of found VGs so that the caller can do autoactivation.
|
||||||
changed = daemon_reply_int(reply, "changed", 0);
|
*
|
||||||
if (!strcmp(status, "partial"))
|
* If there was a problem notifying lvmetad about the new
|
||||||
handler(_lvmetad_cmd, vgname, vgid, 1, changed, CHANGE_AAY);
|
* PV, e.g. lvmetad was disabled due to a duplicate, then
|
||||||
else if (!strcmp(status, "complete"))
|
* no autoactivation is attempted.
|
||||||
handler(_lvmetad_cmd, vgname, vgid, 0, changed, CHANGE_AAY);
|
*
|
||||||
else if (!strcmp(status, "orphan"))
|
* FIXME: there was a previous fixme indicating that
|
||||||
;
|
* autoactivation might also be done for VGs with the
|
||||||
else
|
* "partial" status.
|
||||||
log_error("Request to %s %s in lvmetad gave status %s.",
|
*
|
||||||
"update PV", uuid, status);
|
* If the VG has "changed" by finding the PV, lvmetad returns
|
||||||
|
* the "changed" flag. The names of "changed" VGs are saved
|
||||||
|
* in the changed_vgnames lists, which is used during autoactivation.
|
||||||
|
* If a VG is changed, then autoactivation refreshes LVs in the VG.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (found_vgnames && vgname && status && !strcmp(status, "complete")) {
|
||||||
|
log_debug("VG %s is complete in lvmetad with dev %s.", vgname, dev_name(dev));
|
||||||
|
if (!str_list_add(cmd->mem, found_vgnames, dm_pool_strdup(cmd->mem, vgname)))
|
||||||
|
log_error("str_list_add failed");
|
||||||
|
|
||||||
|
if (changed_vgnames && changed) {
|
||||||
|
log_debug("VG %s is changed in lvmetad.", vgname);
|
||||||
|
if (!str_list_add(cmd->mem, changed_vgnames, dm_pool_strdup(cmd->mem, vgname)))
|
||||||
|
log_error("str_list_add failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
daemon_reply_destroy(reply);
|
daemon_reply_destroy(reply);
|
||||||
@ -1448,7 +1424,7 @@ int lvmetad_pv_found(const struct id *pvid, struct device *dev, const struct for
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lvmetad_pv_gone(dev_t devno, const char *pv_name, activation_handler handler)
|
int lvmetad_pv_gone(dev_t devno, const char *pv_name)
|
||||||
{
|
{
|
||||||
daemon_reply reply;
|
daemon_reply reply;
|
||||||
int result;
|
int result;
|
||||||
@ -1475,9 +1451,9 @@ int lvmetad_pv_gone(dev_t devno, const char *pv_name, activation_handler handler
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lvmetad_pv_gone_by_dev(struct device *dev, activation_handler handler)
|
int lvmetad_pv_gone_by_dev(struct device *dev)
|
||||||
{
|
{
|
||||||
return lvmetad_pv_gone(dev->dev, dev_name(dev), handler);
|
return lvmetad_pv_gone(dev->dev, dev_name(dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1546,10 +1522,8 @@ static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct vo
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (baton.fid->fmt->features & FMT_OBSOLETE) {
|
if (baton.fid->fmt->features & FMT_OBSOLETE) {
|
||||||
log_error("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
|
||||||
baton.fid->fmt->name, dev_name(pvl->pv->dev));
|
|
||||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||||
log_warn("WARNING: Disabling lvmetad cache which does not support obsolete metadata.");
|
log_warn("WARNING: Disabling lvmetad cache which does not support obsolete (lvm1) metadata.");
|
||||||
lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_LVM1);
|
lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_LVM1);
|
||||||
_found_lvm1_metadata = 1;
|
_found_lvm1_metadata = 1;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1635,7 +1609,8 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||||
activation_handler handler, int ignore_obsolete)
|
struct dm_list *found_vgnames,
|
||||||
|
struct dm_list *changed_vgnames)
|
||||||
{
|
{
|
||||||
struct label *label;
|
struct label *label;
|
||||||
struct lvmcache_info *info;
|
struct lvmcache_info *info;
|
||||||
@ -1651,7 +1626,7 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
|||||||
|
|
||||||
if (!label_read(dev, &label, 0)) {
|
if (!label_read(dev, &label, 0)) {
|
||||||
log_print_unless_silent("No PV label found on %s.", dev_name(dev));
|
log_print_unless_silent("No PV label found on %s.", dev_name(dev));
|
||||||
if (!lvmetad_pv_gone_by_dev(dev, handler))
|
if (!lvmetad_pv_gone_by_dev(dev))
|
||||||
goto_bad;
|
goto_bad;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1665,21 +1640,11 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
|||||||
goto_bad;
|
goto_bad;
|
||||||
|
|
||||||
if (baton.fid->fmt->features & FMT_OBSOLETE) {
|
if (baton.fid->fmt->features & FMT_OBSOLETE) {
|
||||||
if (ignore_obsolete)
|
|
||||||
log_warn("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
|
||||||
baton.fid->fmt->name, dev_name(dev));
|
|
||||||
else
|
|
||||||
log_error("Ignoring obsolete format of metadata (%s) on device %s when using lvmetad.",
|
|
||||||
baton.fid->fmt->name, dev_name(dev));
|
|
||||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||||
|
log_warn("WARNING: Disabling lvmetad cache which does not support obsolete (lvm1) metadata.");
|
||||||
log_warn("WARNING: Disabling lvmetad cache which does not support obsolete metadata.");
|
|
||||||
lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_LVM1);
|
lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_LVM1);
|
||||||
_found_lvm1_metadata = 1;
|
_found_lvm1_metadata = 1;
|
||||||
|
return 1;
|
||||||
if (ignore_obsolete)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
|
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
|
||||||
@ -1700,8 +1665,8 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
|||||||
if (!baton.vg)
|
if (!baton.vg)
|
||||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||||
|
|
||||||
if (!lvmetad_pv_found((const struct id *) &dev->pvid, dev, lvmcache_fmt(info),
|
if (!lvmetad_pv_found(cmd, (const struct id *) &dev->pvid, dev, lvmcache_fmt(info),
|
||||||
label->sector, baton.vg, handler)) {
|
label->sector, baton.vg, found_vgnames, changed_vgnames)) {
|
||||||
release_vg(baton.vg);
|
release_vg(baton.vg);
|
||||||
goto_bad;
|
goto_bad;
|
||||||
}
|
}
|
||||||
@ -1738,8 +1703,7 @@ bad:
|
|||||||
* generally revert disk scanning and not use lvmetad.
|
* generally revert disk scanning and not use lvmetad.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler,
|
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait)
|
||||||
int ignore_obsolete, int do_wait)
|
|
||||||
{
|
{
|
||||||
struct dev_iter *iter;
|
struct dev_iter *iter;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
@ -1820,7 +1784,7 @@ static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler
|
|||||||
stack;
|
stack;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!lvmetad_pvscan_single(cmd, dev, handler, ignore_obsolete))
|
if (!lvmetad_pvscan_single(cmd, dev, NULL, NULL))
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1850,20 +1814,6 @@ static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler, int do_wait)
|
|
||||||
{
|
|
||||||
return _lvmetad_pvscan_all_devs(cmd, handler, 0, do_wait);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME Implement this function, skipping PVs known to belong to local or clustered,
|
|
||||||
* non-exported VGs.
|
|
||||||
*/
|
|
||||||
int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handler)
|
|
||||||
{
|
|
||||||
return _lvmetad_pvscan_all_devs(cmd, handler, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg)
|
int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg)
|
||||||
{
|
{
|
||||||
char uuid[64];
|
char uuid[64];
|
||||||
@ -2145,7 +2095,7 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
|
|||||||
* we rescanned for the token, and the time we acquired the global
|
* we rescanned for the token, and the time we acquired the global
|
||||||
* lock.)
|
* lock.)
|
||||||
*/
|
*/
|
||||||
if (!lvmetad_pvscan_all_devs(cmd, NULL, 1)) {
|
if (!lvmetad_pvscan_all_devs(cmd, 1)) {
|
||||||
log_warn("WARNING: Not using lvmetad because cache update failed.");
|
log_warn("WARNING: Not using lvmetad because cache update failed.");
|
||||||
lvmetad_make_unused(cmd);
|
lvmetad_make_unused(cmd);
|
||||||
return;
|
return;
|
||||||
|
27
lib/cache/lvmetad.h
vendored
27
lib/cache/lvmetad.h
vendored
@ -95,15 +95,17 @@ int lvmetad_vg_remove(struct volume_group *vg);
|
|||||||
* number on the cached and on the discovered PV match but the metadata content
|
* number on the cached and on the discovered PV match but the metadata content
|
||||||
* does not.
|
* does not.
|
||||||
*/
|
*/
|
||||||
int lvmetad_pv_found(const struct id *pvid, struct device *dev,
|
int lvmetad_pv_found(struct cmd_context *cmd, const struct id *pvid, struct device *dev,
|
||||||
const struct format_type *fmt, uint64_t label_sector,
|
const struct format_type *fmt, uint64_t label_sector,
|
||||||
struct volume_group *vg, activation_handler handler);
|
struct volume_group *vg,
|
||||||
|
struct dm_list *found_vgnames,
|
||||||
|
struct dm_list *changed_vgnames);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Inform the daemon that the device no longer exists.
|
* Inform the daemon that the device no longer exists.
|
||||||
*/
|
*/
|
||||||
int lvmetad_pv_gone(dev_t devno, const char *pv_name, activation_handler handler);
|
int lvmetad_pv_gone(dev_t devno, const char *pv_name);
|
||||||
int lvmetad_pv_gone_by_dev(struct device *dev, activation_handler handler);
|
int lvmetad_pv_gone_by_dev(struct device *dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Request a list of all PVs available to lvmetad. If requested, this will also
|
* Request a list of all PVs available to lvmetad. If requested, this will also
|
||||||
@ -142,10 +144,10 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd,
|
|||||||
* Scan a single device and update lvmetad with the result(s).
|
* Scan a single device and update lvmetad with the result(s).
|
||||||
*/
|
*/
|
||||||
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||||
activation_handler handler, int ignore_obsolete);
|
struct dm_list *found_vgnames,
|
||||||
|
struct dm_list *changed_vgnames);
|
||||||
|
|
||||||
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler, int do_wait);
|
int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait);
|
||||||
int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handler);
|
|
||||||
|
|
||||||
int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg);
|
int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg);
|
||||||
void lvmetad_validate_global_cache(struct cmd_context *cmd, int force);
|
void lvmetad_validate_global_cache(struct cmd_context *cmd, int force);
|
||||||
@ -170,18 +172,17 @@ void lvmetad_clear_disabled(struct cmd_context *cmd);
|
|||||||
# define lvmetad_release_token() do { } while (0)
|
# define lvmetad_release_token() do { } while (0)
|
||||||
# define lvmetad_vg_update(vg) (1)
|
# define lvmetad_vg_update(vg) (1)
|
||||||
# define lvmetad_vg_remove(vg) (1)
|
# define lvmetad_vg_remove(vg) (1)
|
||||||
# define lvmetad_pv_found(pvid, dev, fmt, label_sector, vg, handler) (1)
|
# define lvmetad_pv_found(cmd, pvid, dev, fmt, label_sector, vg, found_vgnames, changed_vgnames) (1)
|
||||||
# define lvmetad_pv_gone(devno, pv_name, handler) (1)
|
# define lvmetad_pv_gone(devno, pv_name) (1)
|
||||||
# define lvmetad_pv_gone_by_dev(dev, handler) (1)
|
# define lvmetad_pv_gone_by_dev(dev) (1)
|
||||||
# define lvmetad_pv_list_to_lvmcache(cmd) (1)
|
# define lvmetad_pv_list_to_lvmcache(cmd) (1)
|
||||||
# define lvmetad_pv_lookup(cmd, pvid, found) (0)
|
# define lvmetad_pv_lookup(cmd, pvid, found) (0)
|
||||||
# define lvmetad_pv_lookup_by_dev(cmd, dev, found) (0)
|
# define lvmetad_pv_lookup_by_dev(cmd, dev, found) (0)
|
||||||
# define lvmetad_vg_list_to_lvmcache(cmd) (1)
|
# define lvmetad_vg_list_to_lvmcache(cmd) (1)
|
||||||
# define lvmetad_get_vgnameids(cmd, vgnameids) do { } while (0)
|
# define lvmetad_get_vgnameids(cmd, vgnameids) do { } while (0)
|
||||||
# define lvmetad_vg_lookup(cmd, vgname, vgid) (NULL)
|
# define lvmetad_vg_lookup(cmd, vgname, vgid) (NULL)
|
||||||
# define lvmetad_pvscan_single(cmd, dev, handler, ignore_obsolete) (0)
|
# define lvmetad_pvscan_single(cmd, dev, found_vgnames, changed_vgnames) (0)
|
||||||
# define lvmetad_pvscan_all_devs(cmd, handler, do_wait) (0)
|
# define lvmetad_pvscan_all_devs(cmd, do_wait) (0)
|
||||||
# define lvmetad_pvscan_foreign_vgs(cmd, handler) (0)
|
|
||||||
# define lvmetad_vg_clear_outdated_pvs(vg) do { } while (0)
|
# define lvmetad_vg_clear_outdated_pvs(vg) do { } while (0)
|
||||||
# define lvmetad_validate_global_cache(cmd, force) do { } while (0)
|
# define lvmetad_validate_global_cache(cmd, force) do { } while (0)
|
||||||
# define lvmetad_vg_is_foreign(cmd, vgname, vgid) (0)
|
# define lvmetad_vg_is_foreign(cmd, vgname, vgid) (0)
|
||||||
|
@ -5242,7 +5242,7 @@ int scan_vgs_for_pvs(struct cmd_context *cmd, uint32_t warn_flags)
|
|||||||
return _get_pvs(cmd, warn_flags, NULL, NULL);
|
return _get_pvs(cmd, warn_flags, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pv_write(struct cmd_context *cmd __attribute__((unused)),
|
int pv_write(struct cmd_context *cmd,
|
||||||
struct physical_volume *pv, int allow_non_orphan)
|
struct physical_volume *pv, int allow_non_orphan)
|
||||||
{
|
{
|
||||||
if (!pv->fmt->ops->pv_write) {
|
if (!pv->fmt->ops->pv_write) {
|
||||||
@ -5268,8 +5268,7 @@ int pv_write(struct cmd_context *cmd __attribute__((unused)),
|
|||||||
|
|
||||||
pv->status &= ~UNLABELLED_PV;
|
pv->status &= ~UNLABELLED_PV;
|
||||||
|
|
||||||
if (!lvmetad_pv_found(&pv->id, pv->dev, pv->fmt, pv->label_sector,
|
if (!lvmetad_pv_found(cmd, &pv->id, pv->dev, pv->fmt, pv->label_sector, NULL, NULL, NULL))
|
||||||
NULL, NULL))
|
|
||||||
return_0;
|
return_0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -810,7 +810,7 @@ int pvremove_single(struct cmd_context *cmd, const char *pv_name,
|
|||||||
if (info)
|
if (info)
|
||||||
lvmcache_del(info);
|
lvmcache_del(info);
|
||||||
|
|
||||||
if (!lvmetad_pv_gone_by_dev(dev, NULL))
|
if (!lvmetad_pv_gone_by_dev(dev))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
log_print_unless_silent("Labels on physical volume \"%s\" successfully wiped",
|
log_print_unless_silent("Labels on physical volume \"%s\" successfully wiped",
|
||||||
|
@ -37,13 +37,19 @@ aux lvmconf 'global/use_lvmetad = 0'
|
|||||||
check inactive $vg1 foo
|
check inactive $vg1 foo
|
||||||
aux lvmconf 'global/use_lvmetad = 1'
|
aux lvmconf 'global/use_lvmetad = 1'
|
||||||
|
|
||||||
pvscan --cache "$dev2" -aay
|
# Tell lvmetad about dev2, but the VG is not complete with
|
||||||
|
# only dev2, so the -aay should not yet activate the LV.
|
||||||
|
|
||||||
|
pvscan --cache -aay "$dev2"
|
||||||
|
|
||||||
aux lvmconf 'global/use_lvmetad = 0'
|
aux lvmconf 'global/use_lvmetad = 0'
|
||||||
check inactive $vg1 foo
|
check inactive $vg1 foo
|
||||||
aux lvmconf 'global/use_lvmetad = 1'
|
aux lvmconf 'global/use_lvmetad = 1'
|
||||||
|
|
||||||
pvscan --cache "$dev1" -aay
|
# Tell lvmetad about dev1, now the VG is complete with
|
||||||
|
# both devs, so the -aay should activate the LV.
|
||||||
|
|
||||||
|
pvscan --cache -aay "$dev1"
|
||||||
|
|
||||||
aux lvmconf 'global/use_lvmetad = 0'
|
aux lvmconf 'global/use_lvmetad = 0'
|
||||||
check active $vg1 foo
|
check active $vg1 foo
|
||||||
|
@ -1681,7 +1681,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
|
|||||||
*/
|
*/
|
||||||
if (lvmetad_used() && !(cmd->command->flags & NO_LVMETAD_AUTOSCAN)) {
|
if (lvmetad_used() && !(cmd->command->flags & NO_LVMETAD_AUTOSCAN)) {
|
||||||
if (cmd->include_foreign_vgs || !lvmetad_token_matches(cmd)) {
|
if (cmd->include_foreign_vgs || !lvmetad_token_matches(cmd)) {
|
||||||
if (lvmetad_used() && !lvmetad_pvscan_all_devs(cmd, NULL, cmd->include_foreign_vgs ? 1 : 0)) {
|
if (lvmetad_used() && !lvmetad_pvscan_all_devs(cmd, cmd->include_foreign_vgs ? 1 : 0)) {
|
||||||
log_warn("WARNING: Not using lvmetad because cache update failed.");
|
log_warn("WARNING: Not using lvmetad because cache update failed.");
|
||||||
lvmetad_make_unused(cmd);
|
lvmetad_make_unused(cmd);
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ static int _lvscan_single_lvmetad(struct cmd_context *cmd, struct logical_volume
|
|||||||
pvid_s);
|
pvid_s);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!lvmetad_pvscan_single(cmd, pvl->pv->dev, NULL, 0))
|
if (!lvmetad_pvscan_single(cmd, pvl->pv->dev, NULL, NULL))
|
||||||
return ECMD_FAILED;
|
return ECMD_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ int lvscan(struct cmd_context *cmd, int argc, char **argv)
|
|||||||
|
|
||||||
/* Needed because this command has NO_LVMETAD_AUTOSCAN. */
|
/* Needed because this command has NO_LVMETAD_AUTOSCAN. */
|
||||||
if (lvmetad_used() && (!lvmetad_token_matches(cmd) || lvmetad_is_disabled(cmd, &reason))) {
|
if (lvmetad_used() && (!lvmetad_token_matches(cmd) || lvmetad_is_disabled(cmd, &reason))) {
|
||||||
if (lvmetad_used() && !lvmetad_pvscan_all_devs(cmd, NULL, 0)) {
|
if (lvmetad_used() && !lvmetad_pvscan_all_devs(cmd, 0)) {
|
||||||
log_warn("WARNING: Not using lvmetad because cache update failed.");
|
log_warn("WARNING: Not using lvmetad because cache update failed.");
|
||||||
lvmetad_make_unused(cmd);
|
lvmetad_make_unused(cmd);
|
||||||
}
|
}
|
||||||
|
408
tools/pvscan.c
408
tools/pvscan.c
@ -29,6 +29,12 @@ struct pvscan_params {
|
|||||||
char *pv_tmp_name;
|
char *pv_tmp_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct pvscan_aa_params {
|
||||||
|
int refresh_all;
|
||||||
|
unsigned int activate_errors;
|
||||||
|
struct dm_list changed_vgnames;
|
||||||
|
};
|
||||||
|
|
||||||
static int _pvscan_display_single(struct cmd_context *cmd,
|
static int _pvscan_display_single(struct cmd_context *cmd,
|
||||||
struct physical_volume *pv,
|
struct physical_volume *pv,
|
||||||
struct pvscan_params *params)
|
struct pvscan_params *params)
|
||||||
@ -120,70 +126,85 @@ static int _pvscan_single(struct cmd_context *cmd, struct volume_group *vg,
|
|||||||
return ECMD_PROCESSED;
|
return ECMD_PROCESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _lvmetad_clear_dev(dev_t devno, int32_t major, int32_t minor)
|
||||||
|
{
|
||||||
|
char buf[24];
|
||||||
|
|
||||||
|
(void) dm_snprintf(buf, sizeof(buf), FMTi32 ":" FMTi32, major, minor);
|
||||||
|
|
||||||
|
if (!lvmetad_pv_gone(devno, buf))
|
||||||
|
return_0;
|
||||||
|
|
||||||
|
log_print_unless_silent("Device %s not found. Cleared from lvmetad cache.", buf);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pvscan --cache does not perform any lvmlockd locking, and
|
||||||
|
* pvscan --cache -aay skips autoactivation in lockd VGs.
|
||||||
|
*
|
||||||
|
* pvscan --cache populates lvmetad with VG metadata from disk.
|
||||||
|
* No lvmlockd locking is needed. It is expected that lockd VG
|
||||||
|
* metadata that is read by pvscan and populated in lvmetad may
|
||||||
|
* be immediately stale due to changes to the VG from other hosts
|
||||||
|
* during or after this pvscan. This is normal and not a problem.
|
||||||
|
* When a subsequent lvm command uses the VG, it will lock the VG
|
||||||
|
* with lvmlockd, read the VG from lvmetad, and update the cached
|
||||||
|
* copy from disk if necessary.
|
||||||
|
*
|
||||||
|
* pvscan --cache -aay does not activate LVs in lockd VGs because
|
||||||
|
* activation requires locking, and a lock-start operation is needed
|
||||||
|
* on a lockd VG before any locking can be performed in it.
|
||||||
|
*
|
||||||
|
* An equivalent of pvscan --cache -aay for lockd VGs is:
|
||||||
|
* 1. pvscan --cache
|
||||||
|
* 2. vgchange --lock-start
|
||||||
|
* 3. vgchange -aay -S 'locktype=sanlock || locktype=dlm'
|
||||||
|
*
|
||||||
|
* [We could eventually add support for autoactivating lockd VGs
|
||||||
|
* using pvscan by incorporating the lock start step (which can
|
||||||
|
* take a long time), but there may be a better option than
|
||||||
|
* continuing to overload pvscan.]
|
||||||
|
*
|
||||||
|
* Stages of starting a lockd VG:
|
||||||
|
*
|
||||||
|
* . pvscan --cache populates lockd VGs in lvmetad without locks,
|
||||||
|
* and this initial cached copy may quickly become stale.
|
||||||
|
*
|
||||||
|
* . vgchange --lock-start VG reads the VG without the VG lock
|
||||||
|
* because no locks are available until the locking is started.
|
||||||
|
* It only uses the VG name and lock_type from the VG metadata,
|
||||||
|
* and then only uses it to start the VG lockspace in lvmlockd.
|
||||||
|
*
|
||||||
|
* . Further lvm commands, e.g. activation, can then lock the VG
|
||||||
|
* with lvmlockd and use current VG metdata.
|
||||||
|
*/
|
||||||
|
|
||||||
#define REFRESH_BEFORE_AUTOACTIVATION_RETRIES 5
|
#define REFRESH_BEFORE_AUTOACTIVATION_RETRIES 5
|
||||||
#define REFRESH_BEFORE_AUTOACTIVATION_RETRY_USLEEP_DELAY 100000
|
#define REFRESH_BEFORE_AUTOACTIVATION_RETRY_USLEEP_DELAY 100000
|
||||||
|
|
||||||
static int _auto_activation_handler(struct cmd_context *cmd,
|
static int _pvscan_autoactivate_single(struct cmd_context *cmd, const char *vg_name,
|
||||||
const char *vgname, const char *vgid,
|
struct volume_group *vg, struct processing_handle *handle)
|
||||||
int partial, int changed,
|
|
||||||
activation_change_t activate)
|
|
||||||
{
|
{
|
||||||
|
struct pvscan_aa_params *pp = (struct pvscan_aa_params *)handle->custom_handle;
|
||||||
unsigned int refresh_retries = REFRESH_BEFORE_AUTOACTIVATION_RETRIES;
|
unsigned int refresh_retries = REFRESH_BEFORE_AUTOACTIVATION_RETRIES;
|
||||||
int refresh_done = 0;
|
int refresh_done = 0;
|
||||||
struct volume_group *vg;
|
|
||||||
struct id vgid_raw;
|
|
||||||
uint32_t read_error;
|
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
/* TODO: add support for partial and clustered VGs */
|
if (vg_is_clustered(vg))
|
||||||
if (partial)
|
return ECMD_PROCESSED;
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (!id_read_format(&vgid_raw, vgid))
|
if (is_lockd_type(vg->lock_type))
|
||||||
return_0;
|
return ECMD_PROCESSED;
|
||||||
|
|
||||||
|
log_debug("pvscan autoactivating VG %s.", vg_name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: pvscan activation really needs to be changed to use
|
* Refresh LVs in a VG that has "changed" from finding a PV.
|
||||||
* the standard process_each_vg() interface. It should save
|
* The meaning of "changed" is determined in lvmetad, and is
|
||||||
* a list of VG names that are found during the scan, then
|
* returned to the command as a flag.
|
||||||
* call process_each_vg() with that list to do activation.
|
*
|
||||||
*/
|
* FIXME: There's a tiny race when suspending the device which is part
|
||||||
|
|
||||||
cmd->vg_read_print_access_error = 0;
|
|
||||||
|
|
||||||
/* NB. This is safe because we know lvmetad is running and we won't hit disk. */
|
|
||||||
vg = vg_read(cmd, vgname, (const char *)&vgid_raw, 0, 0);
|
|
||||||
read_error = vg_read_error(vg);
|
|
||||||
if (read_error) {
|
|
||||||
/*
|
|
||||||
* foreign VGs: we want to read and update lvmetad, but that's
|
|
||||||
* all, we don't want to even attempt to autoactivate.
|
|
||||||
*
|
|
||||||
* shared VGs: we want to read and update lvmetad, and for now
|
|
||||||
* ignore them for autoactivation. Once pvscan autoactivation
|
|
||||||
* uses process_each_vg, then shared VGs could be autoactivated.
|
|
||||||
*/
|
|
||||||
if (read_error & (FAILED_SYSTEMID | FAILED_LOCK_TYPE | FAILED_LOCK_MODE)) {
|
|
||||||
release_vg(vg);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_error("Failed to read Volume Group \"%s\" (%s) during autoactivation.", vgname, vgid);
|
|
||||||
release_vg(vg);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_lockd_type(vg->lock_type)) {
|
|
||||||
r = 1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vg_is_clustered(vg)) {
|
|
||||||
r = 1;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: There's a tiny race when suspending the device which is part
|
|
||||||
* of the refresh because when suspend ioctl is performed, the dm
|
* of the refresh because when suspend ioctl is performed, the dm
|
||||||
* kernel driver executes (do_suspend and dm_suspend kernel fn):
|
* kernel driver executes (do_suspend and dm_suspend kernel fn):
|
||||||
*
|
*
|
||||||
@ -202,9 +223,10 @@ static int _auto_activation_handler(struct cmd_context *cmd,
|
|||||||
*
|
*
|
||||||
* Remove this workaround with "refresh_retries" once we have proper locking in!
|
* Remove this workaround with "refresh_retries" once we have proper locking in!
|
||||||
*/
|
*/
|
||||||
if (changed) {
|
if (pp->refresh_all || str_list_match_item(&pp->changed_vgnames, vg_name)) {
|
||||||
while (refresh_retries--) {
|
while (refresh_retries--) {
|
||||||
if (vg_refresh_visible(vg->cmd, vg)) {
|
log_debug_activation("Refreshing VG %s before autoactivation.", vg_name);
|
||||||
|
if (vg_refresh_visible(cmd, vg)) {
|
||||||
refresh_done = 1;
|
refresh_done = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -215,8 +237,11 @@ static int _auto_activation_handler(struct cmd_context *cmd,
|
|||||||
log_warn("%s: refresh before autoactivation failed.", vg->name);
|
log_warn("%s: refresh before autoactivation failed.", vg->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vgchange_activate(vg->cmd, vg, activate)) {
|
log_debug_activation("Autoactivating VG %s.", vg_name);
|
||||||
|
|
||||||
|
if (!vgchange_activate(cmd, vg, CHANGE_AAY)) {
|
||||||
log_error("%s: autoactivation failed.", vg->name);
|
log_error("%s: autoactivation failed.", vg->name);
|
||||||
|
pp->activate_errors++;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,35 +251,53 @@ static int _auto_activation_handler(struct cmd_context *cmd,
|
|||||||
* be adding --poll y|n cmdline option for pvscan and call
|
* be adding --poll y|n cmdline option for pvscan and call
|
||||||
* init_background_polling routine in autoactivation handler.
|
* init_background_polling routine in autoactivation handler.
|
||||||
*/
|
*/
|
||||||
if (!(vgchange_background_polling(vg->cmd, vg)))
|
log_debug_activation("Starting background polling for VG %s.", vg_name);
|
||||||
|
|
||||||
|
if (!(vgchange_background_polling(cmd, vg)))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
|
||||||
r = 1;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
unlock_and_release_vg(cmd, vg, vgname);
|
return ECMD_PROCESSED;
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _clear_dev_from_lvmetad_cache(dev_t devno, int32_t major, int32_t minor,
|
static int _pvscan_autoactivate(struct cmd_context *cmd, struct pvscan_aa_params *pp,
|
||||||
activation_handler handler)
|
int all_vgs, struct dm_list *vgnames)
|
||||||
{
|
{
|
||||||
char buf[24];
|
struct processing_handle *handle = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
(void) dm_snprintf(buf, sizeof(buf), FMTi32 ":" FMTi32, major, minor);
|
if (!all_vgs && dm_list_empty(vgnames)) {
|
||||||
|
log_debug("No VGs to autoactivate.");
|
||||||
|
return ECMD_PROCESSED;
|
||||||
|
}
|
||||||
|
|
||||||
if (!lvmetad_pv_gone(devno, buf, handler))
|
if (!lvmetad_used())
|
||||||
return_0;
|
log_warn("WARNING: Autoactivation reading from disk instead of lvmetad.");
|
||||||
|
|
||||||
log_print_unless_silent("Device %s not found. "
|
if (!(handle = init_processing_handle(cmd))) {
|
||||||
"Cleared from lvmetad cache.", buf);
|
log_error("Failed to initialize processing handle.");
|
||||||
|
return ECMD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
handle->custom_handle = pp;
|
||||||
|
|
||||||
|
if (all_vgs) {
|
||||||
|
cmd->command->flags |= ALL_VGS_IS_DEFAULT;
|
||||||
|
pp->refresh_all = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_cache_full_scan(cmd->full_filter);
|
||||||
|
|
||||||
|
ret = process_each_vg(cmd, 0, NULL, NULL, vgnames, 0, handle, _pvscan_autoactivate_single);
|
||||||
|
|
||||||
|
destroy_processing_handle(cmd, handle);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
|
static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
|
||||||
{
|
{
|
||||||
int ret = ECMD_PROCESSED;
|
struct pvscan_aa_params pp = { 0 };
|
||||||
|
struct dm_list found_vgnames;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
const char *pv_name;
|
const char *pv_name;
|
||||||
const char *reason = NULL;
|
const char *reason = NULL;
|
||||||
@ -263,28 +306,26 @@ static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
|
|||||||
int devno_args = 0;
|
int devno_args = 0;
|
||||||
struct arg_value_group_list *current_group;
|
struct arg_value_group_list *current_group;
|
||||||
dev_t devno;
|
dev_t devno;
|
||||||
activation_handler handler = NULL;
|
int do_activate = 0;
|
||||||
|
int all_vgs = 0;
|
||||||
|
int remove_errors = 0;
|
||||||
|
int add_errors = 0;
|
||||||
|
int ret = ECMD_PROCESSED;
|
||||||
|
|
||||||
|
dm_list_init(&found_vgnames);
|
||||||
|
dm_list_init(&pp.changed_vgnames);
|
||||||
|
|
||||||
/*
|
|
||||||
* Return here immediately if lvmetad is not used.
|
|
||||||
* Also return if locking_type=3 (clustered) as we
|
|
||||||
* dont't support cluster + lvmetad yet.
|
|
||||||
*
|
|
||||||
* This is to avoid taking the global lock uselessly
|
|
||||||
* and to prevent hangs in clustered environment.
|
|
||||||
*/
|
|
||||||
/* TODO: Remove this once lvmetad + cluster supported! */
|
|
||||||
if (!lvmetad_used()) {
|
if (!lvmetad_used()) {
|
||||||
log_verbose("Ignoring pvscan --cache command because lvmetad is not in use.");
|
log_verbose("Ignoring pvscan --cache command because lvmetad is not in use.");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg_count(cmd, activate_ARG)) {
|
if (arg_is_set(cmd, activate_ARG)) {
|
||||||
if (arg_uint_value(cmd, activate_ARG, CHANGE_AAY) != CHANGE_AAY) {
|
if (arg_uint_value(cmd, activate_ARG, CHANGE_AAY) != CHANGE_AAY) {
|
||||||
log_error("Only --activate ay allowed with pvscan.");
|
log_error("Only --activate ay allowed with pvscan.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
handler = _auto_activation_handler;
|
do_activate = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg_count(cmd, major_ARG) + arg_count(cmd, minor_ARG))
|
if (arg_count(cmd, major_ARG) + arg_count(cmd, minor_ARG))
|
||||||
@ -300,96 +341,130 @@ static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
|
|||||||
return ECMD_FAILED;
|
return ECMD_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scan everything? */
|
/*
|
||||||
|
* Scan all devices when no args are given.
|
||||||
|
*/
|
||||||
if (!argc && !devno_args) {
|
if (!argc && !devno_args) {
|
||||||
if (!lvmetad_pvscan_all_devs(cmd, handler, 1)) {
|
log_verbose("Scanning all devices.");
|
||||||
log_error("Failed to update cache.");
|
|
||||||
ret = ECMD_FAILED;
|
if (!lvmetad_pvscan_all_devs(cmd, 1)) {
|
||||||
|
log_warn("WARNING: Not using lvmetad because cache update failed.");
|
||||||
|
lvmetad_make_unused(cmd);
|
||||||
}
|
}
|
||||||
goto out;
|
if (lvmetad_used() && lvmetad_is_disabled(cmd, &reason)) {
|
||||||
|
log_warn("WARNING: Not using lvmetad because %s.", reason);
|
||||||
|
lvmetad_make_unused(cmd);
|
||||||
|
}
|
||||||
|
all_vgs = 1;
|
||||||
|
goto activate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: when specific devs are named, we generally don't want to scan
|
||||||
|
* any other devs, but if lvmetad is not yet populated, the first
|
||||||
|
* 'pvscan --cache dev' does need to do a full scan. We want to remove
|
||||||
|
* the need for this case so that 'pvscan --cache dev' is guaranteed to
|
||||||
|
* never scan any devices other than those specified.
|
||||||
|
*/
|
||||||
|
if (!lvmetad_token_matches(cmd)) {
|
||||||
|
log_verbose("Scanning all devices to initialize lvmetad.");
|
||||||
|
|
||||||
|
if (lvmetad_used() && !lvmetad_pvscan_all_devs(cmd, 0)) {
|
||||||
|
log_warn("WARNING: Not using lvmetad because cache update failed.");
|
||||||
|
lvmetad_make_unused(cmd);
|
||||||
|
}
|
||||||
|
if (lvmetad_used() && lvmetad_is_disabled(cmd, &reason)) {
|
||||||
|
log_warn("WARNING: Not using lvmetad because %s.", reason);
|
||||||
|
lvmetad_make_unused(cmd);
|
||||||
|
}
|
||||||
|
all_vgs = 1;
|
||||||
|
goto activate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When lvmetad is disabled, all devices need to be rescanned,
|
* When args are given, scan only those devices. If lvmetad is already
|
||||||
* i.e. the !argc case above, pvscan --cache.
|
* disabled, a full scan is required to reenable it, so there's no
|
||||||
|
* point in doing individual device scans, so go directly to
|
||||||
|
* autoactivation. (FIXME: Should we also skip autoactivation in this
|
||||||
|
* case since that will read disks with lvmetad disabled?
|
||||||
|
* i.e. avoid disk access and not activate LVs, or or read from disk
|
||||||
|
* and activate LVs?)
|
||||||
*/
|
*/
|
||||||
if (lvmetad_used() && lvmetad_is_disabled(cmd, &reason)) {
|
if (lvmetad_is_disabled(cmd, &reason)) {
|
||||||
log_warn("WARNING: Not using lvmetad because %s.", reason);
|
log_warn("WARNING: Not using lvmetad because %s.", reason);
|
||||||
log_warn("WARNING: Rescan all devices to update lvmetad cache (pvscan --cache).");
|
lvmetad_make_unused(cmd);
|
||||||
log_error("Failed to update cache.");
|
all_vgs = 1;
|
||||||
ret = ECMD_FAILED;
|
goto activate;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: when specific devs are named, we generally don't
|
* Step 1: for each device, if it's no longer found, then tell lvmetad
|
||||||
* want to scan any other devs, but if lvmetad is not yet
|
* to drop it. If the device exists, read metadata from it and send
|
||||||
* populated, the first 'pvscan --cache dev' does need to
|
* that to lvmetad.
|
||||||
* do a full scan. We want to remove the need for this
|
*
|
||||||
* case so that 'pvscan --cache dev' is guaranteed to never
|
* When given a device name, check if the device is not visible to
|
||||||
* scan any devices other than those specified.
|
* lvmetad, but still visible to the system, and if so, tell lvmetad to
|
||||||
|
* drop it (using the major:minor from the system).
|
||||||
|
*
|
||||||
|
* When given a major:minor which is not visible to the system, just
|
||||||
|
* tell lvmetad to drop it directly using that major:minor.
|
||||||
|
*
|
||||||
|
* When a device has left the system, it must be dropped using
|
||||||
|
* --major/--minor because we cannot map the device name to major:minor
|
||||||
|
* after the device has left. (A full rescan could of course be used
|
||||||
|
* to drop any devices that have left.)
|
||||||
*/
|
*/
|
||||||
if (lvmetad_used() && !lvmetad_token_matches(cmd)) {
|
|
||||||
if (lvmetad_used() && !lvmetad_pvscan_all_devs(cmd, NULL, 0)) {
|
|
||||||
log_error("Failed to update cache.");
|
|
||||||
ret = ECMD_FAILED;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log_verbose("Using physical volume(s) on command line");
|
if (argc || devno_args)
|
||||||
|
log_verbose("Scanning devices on command line.");
|
||||||
|
|
||||||
/* Process any command line PVs first. */
|
|
||||||
while (argc--) {
|
while (argc--) {
|
||||||
pv_name = *argv++;
|
pv_name = *argv++;
|
||||||
if (pv_name[0] == '/') {
|
if (pv_name[0] == '/') {
|
||||||
/* device path */
|
|
||||||
if (!(dev = dev_cache_get(pv_name, cmd->lvmetad_filter))) {
|
if (!(dev = dev_cache_get(pv_name, cmd->lvmetad_filter))) {
|
||||||
|
/* Remove device path from lvmetad. */
|
||||||
|
log_debug("Removing dev %s from lvmetad cache.", pv_name);
|
||||||
if ((dev = dev_cache_get(pv_name, NULL))) {
|
if ((dev = dev_cache_get(pv_name, NULL))) {
|
||||||
if (!_clear_dev_from_lvmetad_cache(dev->dev, MAJOR(dev->dev), MINOR(dev->dev), handler)) {
|
if (!_lvmetad_clear_dev(dev->dev, MAJOR(dev->dev), MINOR(dev->dev)))
|
||||||
stack;
|
remove_errors++;
|
||||||
ret = ECMD_FAILED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
log_error("Physical Volume %s not found.", pv_name);
|
log_error("Physical Volume %s not found.", pv_name);
|
||||||
ret = ECMD_FAILED;
|
ret = ECMD_FAILED;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
continue;
|
} else {
|
||||||
|
/* Add device path to lvmetad. */
|
||||||
|
log_debug("Scanning dev %s for lvmetad cache.", pv_name);
|
||||||
|
if (!lvmetad_pvscan_single(cmd, dev, &found_vgnames, &pp.changed_vgnames))
|
||||||
|
add_errors++;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
/* device major:minor */
|
|
||||||
if (sscanf(pv_name, "%d:%d", &major, &minor) != 2) {
|
if (sscanf(pv_name, "%d:%d", &major, &minor) != 2) {
|
||||||
log_error("Failed to parse major:minor from %s", pv_name);
|
log_warn("WARNING: Failed to parse major:minor from %s, skipping.", pv_name);
|
||||||
ret = ECMD_FAILED;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
devno = MKDEV((dev_t)major, (dev_t)minor);
|
devno = MKDEV((dev_t)major, (dev_t)minor);
|
||||||
|
|
||||||
if (!(dev = dev_cache_get_by_devt(devno, cmd->lvmetad_filter))) {
|
if (!(dev = dev_cache_get_by_devt(devno, cmd->lvmetad_filter))) {
|
||||||
if (!(_clear_dev_from_lvmetad_cache(devno, major, minor, handler))) {
|
/* Remove major:minor from lvmetad. */
|
||||||
stack;
|
log_debug("Removing dev %d:%d from lvmetad cache.", major, minor);
|
||||||
ret = ECMD_FAILED;
|
if (!_lvmetad_clear_dev(devno, major, minor))
|
||||||
break;
|
remove_errors++;
|
||||||
}
|
} else {
|
||||||
continue;
|
/* Add major:minor to lvmetad. */
|
||||||
|
log_debug("Scanning dev %d:%d for lvmetad cache.", major, minor);
|
||||||
|
if (!lvmetad_pvscan_single(cmd, dev, &found_vgnames, &pp.changed_vgnames))
|
||||||
|
add_errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sigint_caught()) {
|
if (sigint_caught()) {
|
||||||
ret = ECMD_FAILED;
|
ret = ECMD_FAILED;
|
||||||
stack;
|
goto_out;
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!lvmetad_pvscan_single(cmd, dev, handler, 0)) {
|
|
||||||
ret = ECMD_FAILED;
|
|
||||||
stack;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!devno_args)
|
if (!devno_args)
|
||||||
goto out;
|
goto activate;
|
||||||
|
|
||||||
/* Process any grouped --major --minor args */
|
/* Process any grouped --major --minor args */
|
||||||
dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
|
dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
|
||||||
@ -402,27 +477,47 @@ static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
|
|||||||
devno = MKDEV((dev_t)major, (dev_t)minor);
|
devno = MKDEV((dev_t)major, (dev_t)minor);
|
||||||
|
|
||||||
if (!(dev = dev_cache_get_by_devt(devno, cmd->lvmetad_filter))) {
|
if (!(dev = dev_cache_get_by_devt(devno, cmd->lvmetad_filter))) {
|
||||||
if (!(_clear_dev_from_lvmetad_cache(devno, major, minor, handler))) {
|
/* Remove major:minor from lvmetad. */
|
||||||
stack;
|
log_debug("Removing dev %d:%d from lvmetad cache.", major, minor);
|
||||||
ret = ECMD_FAILED;
|
if (!_lvmetad_clear_dev(devno, major, minor))
|
||||||
break;
|
remove_errors++;
|
||||||
}
|
} else {
|
||||||
continue;
|
/* Add major:minor to lvmetad. */
|
||||||
|
log_debug("Scanning dev %d:%d for lvmetad cache.", major, minor);
|
||||||
|
if (!lvmetad_pvscan_single(cmd, dev, &found_vgnames, &pp.changed_vgnames))
|
||||||
|
add_errors++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sigint_caught()) {
|
if (sigint_caught()) {
|
||||||
ret = ECMD_FAILED;
|
ret = ECMD_FAILED;
|
||||||
stack;
|
goto_out;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (!lvmetad_pvscan_single(cmd, dev, handler, 0)) {
|
|
||||||
ret = ECMD_FAILED;
|
|
||||||
stack;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In the process of scanning devices, lvmetad may have become
|
||||||
|
* disabled. If so, revert to scanning for the autoactivation step.
|
||||||
|
* Only autoactivate the VGs that were found during the dev scans.
|
||||||
|
*/
|
||||||
|
if (lvmetad_used() && lvmetad_is_disabled(cmd, &reason)) {
|
||||||
|
log_warn("WARNING: Not using lvmetad because %s.", reason);
|
||||||
|
lvmetad_make_unused(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
activate:
|
||||||
|
/*
|
||||||
|
* Step 2: when the PV was sent to lvmetad, the lvmetad reply
|
||||||
|
* indicated if all the PVs for the VG are now found. If so,
|
||||||
|
* the vgname was added to the list, and we can attempt to
|
||||||
|
* autoactivate LVs in the VG.
|
||||||
|
*/
|
||||||
|
if (do_activate)
|
||||||
|
ret = _pvscan_autoactivate(cmd, &pp, all_vgs, &found_vgnames);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
if (remove_errors || add_errors || pp.activate_errors)
|
||||||
|
ret = ECMD_FAILED;
|
||||||
|
|
||||||
if (!sync_local_dev_names(cmd))
|
if (!sync_local_dev_names(cmd))
|
||||||
stack;
|
stack;
|
||||||
unlock_vg(cmd, VG_GLOBAL);
|
unlock_vg(cmd, VG_GLOBAL);
|
||||||
@ -477,7 +572,7 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (arg_count(cmd, cache_long_ARG))
|
if (arg_count(cmd, cache_long_ARG))
|
||||||
return _pvscan_lvmetad(cmd, argc, argv);
|
return _pvscan_cache(cmd, argc, argv);
|
||||||
|
|
||||||
if (argc) {
|
if (argc) {
|
||||||
log_error("Too many parameters on command line.");
|
log_error("Too many parameters on command line.");
|
||||||
@ -506,7 +601,7 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv)
|
|||||||
|
|
||||||
/* Needed because this command has NO_LVMETAD_AUTOSCAN. */
|
/* Needed because this command has NO_LVMETAD_AUTOSCAN. */
|
||||||
if (lvmetad_used() && (!lvmetad_token_matches(cmd) || lvmetad_is_disabled(cmd, &reason))) {
|
if (lvmetad_used() && (!lvmetad_token_matches(cmd) || lvmetad_is_disabled(cmd, &reason))) {
|
||||||
if (lvmetad_used() && !lvmetad_pvscan_all_devs(cmd, NULL, 0)) {
|
if (lvmetad_used() && !lvmetad_pvscan_all_devs(cmd, 0)) {
|
||||||
log_warn("WARNING: Not using lvmetad because cache update failed.");
|
log_warn("WARNING: Not using lvmetad because cache update failed.");
|
||||||
lvmetad_make_unused(cmd);
|
lvmetad_make_unused(cmd);
|
||||||
}
|
}
|
||||||
@ -526,7 +621,6 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv)
|
|||||||
if (!lockd_gl(cmd, "sh", 0))
|
if (!lockd_gl(cmd, "sh", 0))
|
||||||
return_ECMD_FAILED;
|
return_ECMD_FAILED;
|
||||||
|
|
||||||
|
|
||||||
if (!(handle = init_processing_handle(cmd))) {
|
if (!(handle = init_processing_handle(cmd))) {
|
||||||
log_error("Failed to initialize processing handle.");
|
log_error("Failed to initialize processing handle.");
|
||||||
ret = ECMD_FAILED;
|
ret = ECMD_FAILED;
|
||||||
|
@ -4624,7 +4624,7 @@ do_command:
|
|||||||
if (info)
|
if (info)
|
||||||
lvmcache_del(info);
|
lvmcache_del(info);
|
||||||
|
|
||||||
if (!lvmetad_pv_gone_by_dev(pd->dev, NULL)) {
|
if (!lvmetad_pv_gone_by_dev(pd->dev)) {
|
||||||
log_error("Failed to remove PV %s from lvmetad.", pd->name);
|
log_error("Failed to remove PV %s from lvmetad.", pd->name);
|
||||||
dm_list_move(&pp->arg_fail, &pd->list);
|
dm_list_move(&pp->arg_fail, &pd->list);
|
||||||
continue;
|
continue;
|
||||||
@ -4644,7 +4644,7 @@ do_command:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lvmetad_pv_gone_by_dev(pd->dev, NULL)) {
|
if (!lvmetad_pv_gone_by_dev(pd->dev)) {
|
||||||
log_error("Failed to remove PV %s from lvmetad.", pd->name);
|
log_error("Failed to remove PV %s from lvmetad.", pd->name);
|
||||||
dm_list_move(&pp->arg_fail, &pd->list);
|
dm_list_move(&pp->arg_fail, &pd->list);
|
||||||
continue;
|
continue;
|
||||||
|
@ -96,7 +96,7 @@ int vgimport(struct cmd_context *cmd, int argc, char **argv)
|
|||||||
* import it.
|
* import it.
|
||||||
*/
|
*/
|
||||||
if (lvmetad_used()) {
|
if (lvmetad_used()) {
|
||||||
if (!lvmetad_pvscan_all_devs(cmd, NULL, 1)) {
|
if (!lvmetad_pvscan_all_devs(cmd, 1)) {
|
||||||
log_warn("WARNING: Not using lvmetad because cache update failed.");
|
log_warn("WARNING: Not using lvmetad because cache update failed.");
|
||||||
lvmetad_make_unused(cmd);
|
lvmetad_make_unused(cmd);
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ int vgscan(struct cmd_context *cmd, int argc, char **argv)
|
|||||||
log_verbose("Ignoring vgscan --cache command because lvmetad is not in use.");
|
log_verbose("Ignoring vgscan --cache command because lvmetad is not in use.");
|
||||||
|
|
||||||
if (lvmetad_used() && (arg_is_set(cmd, cache_long_ARG) || !lvmetad_token_matches(cmd) || lvmetad_is_disabled(cmd, &reason))) {
|
if (lvmetad_used() && (arg_is_set(cmd, cache_long_ARG) || !lvmetad_token_matches(cmd) || lvmetad_is_disabled(cmd, &reason))) {
|
||||||
if (lvmetad_used() && !lvmetad_pvscan_all_devs(cmd, NULL, arg_is_set(cmd, cache_long_ARG))) {
|
if (lvmetad_used() && !lvmetad_pvscan_all_devs(cmd, arg_is_set(cmd, cache_long_ARG))) {
|
||||||
log_warn("WARNING: Not using lvmetad because cache update failed.");
|
log_warn("WARNING: Not using lvmetad because cache update failed.");
|
||||||
lvmetad_make_unused(cmd);
|
lvmetad_make_unused(cmd);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user