unsigned vg_use_count; /* Counter of vg reusage */
unsigned precommitted; /* Is vgmetadata live or precommitted? */
unsigned cached_vg_invalidated; /* Signal to regenerate cached_vg */
+ int independent_metadata_location; /* metadata read from independent areas */
};
static struct dm_hash_table *_pvid_hash = NULL;
{
struct lvmcache_vginfo *vginfo;
struct lvmcache_info *info;
- struct label *label;
struct dm_list *devh, *tmp;
struct dm_list devs;
struct device_list *devl;
dm_list_iterate_safe(devh, tmp, &devs) {
devl = dm_list_item(devh, struct device_list);
- (void) label_read(devl->dev, &label, UINT64_C(0));
+ label_read(devl->dev, NULL, UINT64_C(0));
dm_list_del(&devl->list);
dm_free(devl);
}
struct lvmcache_info *info;
char *vgname;
- if (!lvmcache_device_from_pvid(cmd, (const struct id *)pvid, NULL, NULL)) {
+ if (!lvmcache_device_from_pvid(cmd, (const struct id *)pvid, NULL)) {
log_error("Couldn't find device with uuid %s.", pvid);
return NULL;
}
return vgname;
}
-static void _rescan_entry(struct lvmcache_info *info)
+/*
+ * FIXME: get rid of the CACHE_INVALID state and rescanning
+ * infos with that flag. The code should just know which devices
+ * need scanning and when.
+ */
+static int _label_scan_invalid(struct cmd_context *cmd)
{
- struct label *label;
+ struct dm_list devs;
+ struct dm_hash_node *n;
+ struct device_list *devl;
+ struct lvmcache_info *info;
+ int dev_count = 0;
+ int ret;
- if (info->status & CACHE_INVALID)
- (void) label_read(info->dev, &label, UINT64_C(0));
-}
+ dm_list_init(&devs);
-static int _scan_invalid(void)
-{
- dm_hash_iter(_pvid_hash, (dm_hash_iterate_fn) _rescan_entry);
+ dm_hash_iterate(n, _pvid_hash) {
+ if (!(info = dm_hash_get_data(_pvid_hash, n)))
+ continue;
- return 1;
+ if (!(info->status & CACHE_INVALID))
+ continue;
+
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return_0;
+
+ devl->dev = info->dev;
+ dm_list_add(&devs, &devl->list);
+ dev_count++;
+ }
+
+ log_debug_cache("Scanning %d devs with invalid info.", dev_count);
+
+ ret = label_scan_devs(cmd, &devs);
+
+ return ret;
}
/*
goto next;
}
+/*
+ * The initial label_scan at the start of the command is done without
+ * holding VG locks. Then for each VG identified during the label_scan,
+ * vg_read(vgname) is called while holding the VG lock. The labels
+ * and metadata on this VG's devices could have changed between the
+ * initial unlocked label_scan and the current vg_read(). So, we reread
+ * the labels/metadata for each device in the VG now that we hold the
+ * lock, and use this for processing the VG.
+ *
+ * FIXME: In some cases, the data read by label_scan may be fine, and not
+ * need to be reread here. e.g. a reporting command, possibly with a
+ * special option, could skip this second reread. Or, we could look
+ * at the VG seqno in each copy of the metadata read in the first label
+ * scan, and if they all match, consider it good enough to use for
+ * reporting without rereading it. (A command modifying the VG would
+ * always want to reread while the lock is held before modifying.)
+ *
+ * A label scan is ultimately creating associations between devices
+ * and VGs so that when vg_read wants to get VG metadata, it knows
+ * which devices to read. In the special case where VG metadata is
+ * stored in files on the file system (configured in lvm.conf), the
+ * vginfo->independent_metadata_location flag is set during label scan.
+ * When we get here to rescan, we are revalidating the device to VG
+ * mapping from label scan by repeating the label scan on a subset of
+ * devices. If we see independent_metadata_location is set from the
+ * initial label scan, we know that there is nothing to do because
+ * there is no device to VG mapping to revalidate, since the VG metadata
+ * comes directly from files.
+ */
+
+int lvmcache_label_rescan_vg(struct cmd_context *cmd, const char *vgname, const char *vgid)
+{
+ struct dm_list devs;
+ struct device_list *devl;
+ struct lvmcache_vginfo *vginfo;
+ struct lvmcache_info *info;
+
+ if (lvmetad_used())
+ return 1;
+
+ dm_list_init(&devs);
+
+ if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid)))
+ return_0;
+
+ /*
+ * When the VG metadata is from an independent location,
+ * then rescanning the devices in the VG won't find the
+ * metadata, and will destroy the vginfo/info associations
+ * that were created during label scan when the
+ * independent locations were read.
+ */
+ if (vginfo->independent_metadata_location)
+ return 1;
+
+ dm_list_iterate_items(info, &vginfo->infos) {
+ if (!(devl = dm_malloc(sizeof(*devl)))) {
+ log_error("device_list element allocation failed");
+ return 0;
+ }
+ devl->dev = info->dev;
+ dm_list_add(&devs, &devl->list);
+ }
+
+ label_scan_devs(cmd, &devs);
+
+ /*
+ * TODO: grab vginfo again, and compare vginfo->infos
+ * to what was found above before rereading labels.
+ * If there are any info->devs now that were not in the
+ * first devs list, then do label_read on those also.
+ */
+
+ return 1;
+}
+
int lvmcache_label_scan(struct cmd_context *cmd)
{
struct dm_list del_cache_devs;
struct dm_list add_cache_devs;
struct lvmcache_info *info;
struct device_list *devl;
- struct label *label;
- struct dev_iter *iter;
- struct device *dev;
struct format_type *fmt;
- int dev_count = 0;
int r = 0;
goto out;
}
+ /*
+ * Scan devices whose info struct has the INVALID flag set.
+ * When scanning has read the pv_header, mda_header and
+ * mda locations, it will clear the INVALID flag (via
+ * lvmcache_make_valid).
+ */
if (_has_scanned && !_force_label_scan) {
- r = _scan_invalid();
+ r = _label_scan_invalid(cmd);
goto out;
}
if (_force_label_scan && (cmd->full_filter && !cmd->full_filter->use_count) && !refresh_filters(cmd))
goto_out;
- if (!cmd->full_filter || !(iter = dev_iter_create(cmd->full_filter, _force_label_scan))) {
- log_error("dev_iter creation failed");
+ if (!cmd->full_filter) {
+ log_error("label scan is missing full filter");
goto out;
}
- log_very_verbose("Scanning device labels");
-
/*
* Duplicates found during this label scan are added to _found_duplicate_devs().
*/
_destroy_duplicate_device_list(&_found_duplicate_devs);
- while ((dev = dev_iter_get(iter))) {
- (void) label_read(dev, &label, UINT64_C(0));
- dev_count++;
- }
-
- dev_iter_destroy(iter);
-
- log_very_verbose("Scanned %d device labels", dev_count);
+ /*
+ * Do the actual scanning. This populates lvmcache
+ * with infos/vginfos based on reading headers from
+ * each device, and a vg summary from each mda.
+ *
+ * Note that this will *skip* scanning a device if
+ * an info struct already exists in lvmcache for
+ * the device.
+ */
+ label_scan(cmd);
/*
* _choose_preferred_devs() returns:
dm_list_iterate_items(devl, &add_cache_devs) {
log_debug_cache("Rescan preferred device %s for lvmcache", dev_name(devl->dev));
- (void) label_read(devl->dev, &label, UINT64_C(0));
+ label_read(devl->dev, NULL, UINT64_C(0));
}
dm_list_splice(&_unused_duplicate_devs, &del_cache_devs);
return pvids;
}
-static struct device *_device_from_pvid(const struct id *pvid,
- uint64_t *label_sector)
+int lvmcache_get_vg_devs(struct cmd_context *cmd,
+ struct lvmcache_vginfo *vginfo,
+ struct dm_list *devs)
{
struct lvmcache_info *info;
- struct label *label;
+ struct device_list *devl;
- if ((info = lvmcache_info_from_pvid((const char *) pvid, NULL, 0))) {
- if (lvmetad_used()) {
- if (info->label && label_sector)
- *label_sector = info->label->sector;
- return info->dev;
- }
+ dm_list_iterate_items(info, &vginfo->infos) {
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return_0;
- if (label_read(info->dev, &label, UINT64_C(0))) {
- info = (struct lvmcache_info *) label->info;
- if (id_equal(pvid, (struct id *) &info->dev->pvid)) {
- if (label_sector)
- *label_sector = label->sector;
- return info->dev;
- }
- }
+ devl->dev = info->dev;
+ dm_list_add(devs, &devl->list);
}
- return NULL;
+ return 1;
}
-struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
- unsigned *scan_done_once, uint64_t *label_sector)
+static struct device *_device_from_pvid(const struct id *pvid, uint64_t *label_sector)
{
- struct device *dev;
-
- /* Already cached ? */
- dev = _device_from_pvid(pvid, label_sector);
- if (dev)
- return dev;
-
- lvmcache_label_scan(cmd);
+ struct lvmcache_info *info;
- /* Try again */
- dev = _device_from_pvid(pvid, label_sector);
- if (dev)
- return dev;
+ if ((info = lvmcache_info_from_pvid((const char *) pvid, NULL, 0))) {
+ if (info->label && label_sector)
+ *label_sector = info->label->sector;
+ return info->dev;
+ }
- if (critical_section() || (scan_done_once && *scan_done_once))
- return NULL;
+ return NULL;
+}
- lvmcache_force_next_label_scan();
- lvmcache_label_scan(cmd);
- if (scan_done_once)
- *scan_done_once = 1;
+struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid, uint64_t *label_sector)
+{
+ struct device *dev;
- /* Try again */
dev = _device_from_pvid(pvid, label_sector);
if (dev)
return dev;
+ log_debug_devs("No device with uuid %s.", (const char *)pvid);
return NULL;
}
const char *devname)
{
struct device *dev;
- struct label *label;
if (!(dev = dev_cache_get(devname, cmd->filter))) {
log_error("%s: Couldn't find device. Check your filters?",
return NULL;
}
- if (!(label_read(dev, &label, UINT64_C(0))))
+ if (!(label_read(dev, NULL, UINT64_C(0))))
return NULL;
return dev->pvid;
return 1;
}
+void lvmcache_set_independent_location(const char *vgname)
+{
+ struct lvmcache_vginfo *vginfo;
+
+ if ((vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
+ vginfo->independent_metadata_location = 1;
+}
+
/*
* Return true iff it is impossible to find out from this info alone whether the
* PV in question is or is not an orphan.