diff options
Diffstat (limited to 'lib/cache/lvmcache.c')
-rw-r--r-- | lib/cache/lvmcache.c | 667 |
1 files changed, 560 insertions, 107 deletions
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c index d545563..2c431b1 100644 --- a/lib/cache/lvmcache.c +++ b/lib/cache/lvmcache.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * @@ -26,6 +26,46 @@ #include "format-text.h" #include "format_pool.h" #include "format1.h" +#include "config.h" + +#include "lvmetad.h" + +#define CACHE_INVALID 0x00000001 +#define CACHE_LOCKED 0x00000002 + +/* One per device */ +struct lvmcache_info { + struct dm_list list; /* Join VG members together */ + struct dm_list mdas; /* list head for metadata areas */ + struct dm_list das; /* list head for data areas */ + struct lvmcache_vginfo *vginfo; /* NULL == unknown */ + struct label *label; + const struct format_type *fmt; + struct device *dev; + uint64_t device_size; /* Bytes */ + uint32_t status; +}; + +/* One per VG */ +struct lvmcache_vginfo { + struct dm_list list; /* Join these vginfos together */ + struct dm_list infos; /* List head for lvmcache_infos */ + const struct format_type *fmt; + char *vgname; /* "" == orphan */ + uint32_t status; + char vgid[ID_LEN + 1]; + char _padding[7]; + struct lvmcache_vginfo *next; /* Another VG with same name? */ + char *creation_host; + size_t vgmetadata_size; + char *vgmetadata; /* Copy of VG metadata as format_text string */ + struct dm_config_tree *cft; /* Config tree created from vgmetadata */ + /* Lifetime is directly tied to vgmetadata */ + struct volume_group *cached_vg; + unsigned holders; + unsigned vg_use_count; /* Counter of vg reusage */ + unsigned precommitted; /* Is vgmetadata live or precommitted? */ +}; static struct dm_hash_table *_pvid_hash = NULL; static struct dm_hash_table *_vgid_hash = NULL; @@ -72,6 +112,19 @@ int lvmcache_init(void) return 1; } +void lvmcache_seed_infos_from_lvmetad(struct cmd_context *cmd) +{ + if (!lvmetad_active() || _has_scanned) + return; + + if (!lvmetad_pv_list_to_lvmcache(cmd)) { + stack; + return; + } + + _has_scanned = 1; +} + /* Volume Group metadata cache functions */ static void _free_cached_vgmetadata(struct lvmcache_vginfo *vginfo) { @@ -82,7 +135,15 @@ static void _free_cached_vgmetadata(struct lvmcache_vginfo *vginfo) vginfo->vgmetadata = NULL; + /* Release also cached config tree */ + if (vginfo->cft) { + dm_config_destroy(vginfo->cft); + vginfo->cft = NULL; + } + log_debug("Metadata cache: VG %s wiped.", vginfo->vgname); + + release_vg(vginfo->cached_vg); } /* @@ -92,21 +153,30 @@ static void _store_metadata(struct volume_group *vg, unsigned precommitted) { char uuid[64] __attribute__((aligned(8))); struct lvmcache_vginfo *vginfo; - int size; + char *data; + size_t size; - if (!(vginfo = vginfo_from_vgid((const char *)&vg->id))) { + if (!(vginfo = lvmcache_vginfo_from_vgid((const char *)&vg->id))) { stack; return; } - if (vginfo->vgmetadata) - _free_cached_vgmetadata(vginfo); - - if (!(size = export_vg_to_buffer(vg, &vginfo->vgmetadata))) { + if (!(size = export_vg_to_buffer(vg, &data))) { stack; + _free_cached_vgmetadata(vginfo); return; } + /* Avoid reparsing of the same data string */ + if (vginfo->vgmetadata && vginfo->vgmetadata_size == size && + strcmp(vginfo->vgmetadata, data) == 0) + dm_free(data); + else { + _free_cached_vgmetadata(vginfo); + vginfo->vgmetadata_size = size; + vginfo->vgmetadata = data; + } + vginfo->precommitted = precommitted; if (!id_write_format((const struct id *)vginfo->vgid, uuid, sizeof(uuid))) { @@ -114,7 +184,7 @@ static void _store_metadata(struct volume_group *vg, unsigned precommitted) return; } - log_debug("Metadata cache: VG %s (%s) stored (%d bytes%s).", + log_debug("Metadata cache: VG %s (%s) stored (%" PRIsize_t " bytes%s).", vginfo->vgname, uuid, size, precommitted ? ", precommitted" : ""); } @@ -129,7 +199,7 @@ static void _update_cache_info_lock_state(struct lvmcache_info *info, * Cache becomes invalid whenever lock state changes unless * exclusive VG_GLOBAL is held (i.e. while scanning). */ - if (!vgname_is_locked(VG_GLOBAL) && (was_locked != locked)) { + if (!lvmcache_vgname_is_locked(VG_GLOBAL) && (was_locked != locked)) { info->status |= CACHE_INVALID; *cached_vgmetadata_valid = 0; } @@ -158,7 +228,7 @@ static void _update_cache_lock_state(const char *vgname, int locked) { struct lvmcache_vginfo *vginfo; - if (!(vginfo = vginfo_from_vgname(vgname, NULL))) + if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL))) return; _update_cache_vginfo_lock_state(vginfo, locked); @@ -169,7 +239,7 @@ static void _drop_metadata(const char *vgname, int drop_precommitted) struct lvmcache_vginfo *vginfo; struct lvmcache_info *info; - if (!(vginfo = vginfo_from_vgname(vgname, NULL))) + if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL))) return; /* @@ -187,6 +257,10 @@ static void _drop_metadata(const char *vgname, int drop_precommitted) info->status |= CACHE_INVALID; _free_cached_vgmetadata(vginfo); + + /* VG revert */ + if (drop_precommitted) + vginfo->precommitted = 0; } /* @@ -198,7 +272,7 @@ void lvmcache_commit_metadata(const char *vgname) { struct lvmcache_vginfo *vginfo; - if (!(vginfo = vginfo_from_vgname(vgname, NULL))) + if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL))) return; if (vginfo->precommitted) { @@ -218,7 +292,7 @@ void lvmcache_drop_metadata(const char *vgname, int drop_precommitted) /* Indicate that PVs could now be missing from the cache */ init_full_scan_done(0); - } else if (!vgname_is_locked(VG_GLOBAL)) + } else if (!lvmcache_vgname_is_locked(VG_GLOBAL)) _drop_metadata(vgname, drop_precommitted); } @@ -262,13 +336,17 @@ int lvmcache_verify_lock_order(const char *vgname) if (!dm_hash_get_data(_lock_hash, n)) return_0; - vgname2 = dm_hash_get_key(_lock_hash, n); + if (!(vgname2 = dm_hash_get_key(_lock_hash, n))) { + log_error(INTERNAL_ERROR "VG lock %s hits NULL.", + vgname); + return 0; + } if (!_vgname_order_correct(vgname2, vgname)) { log_errno(EDEADLK, INTERNAL_ERROR "VG lock %s must " "be requested before %s, not after.", vgname, vgname2); - return_0; + return 0; } } @@ -295,7 +373,7 @@ void lvmcache_lock_vgname(const char *vgname, int read_only __attribute__((unuse _vgs_locked++; } -int vgname_is_locked(const char *vgname) +int lvmcache_vgname_is_locked(const char *vgname) { if (!_lock_hash) return 0; @@ -318,7 +396,7 @@ void lvmcache_unlock_vgname(const char *vgname) dev_close_all(); } -int vgs_locked(void) +int lvmcache_vgs_locked(void) { return _vgs_locked; } @@ -344,12 +422,12 @@ static void _vginfo_detach_info(struct lvmcache_info *info) } /* If vgid supplied, require a match. */ -struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname, const char *vgid) +struct lvmcache_vginfo *lvmcache_vginfo_from_vgname(const char *vgname, const char *vgid) { struct lvmcache_vginfo *vginfo; if (!vgname) - return vginfo_from_vgid(vgid); + return lvmcache_vginfo_from_vgid(vgid); if (!_vgname_hash) return NULL; @@ -366,7 +444,9 @@ struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname, const char *vgid) return vginfo; } -const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid, unsigned revalidate_labels) +const struct format_type *lvmcache_fmt_from_vgname(struct cmd_context *cmd, + const char *vgname, const char *vgid, + unsigned revalidate_labels) { struct lvmcache_vginfo *vginfo; struct lvmcache_info *info; @@ -374,10 +454,22 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid, struct dm_list *devh, *tmp; struct dm_list devs; struct device_list *devl; + struct volume_group *vg; + const struct format_type *fmt; char vgid_found[ID_LEN + 1] __attribute__((aligned(8))); - if (!(vginfo = vginfo_from_vgname(vgname, vgid))) + if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) { + if (!lvmetad_active()) + return NULL; /* too bad */ + /* If we don't have the info but we have lvmetad, we can ask + * there before failing. */ + if ((vg = lvmetad_vg_lookup(cmd, vgname, vgid))) { + fmt = vg->fid->fmt; + release_vg(vg); + return fmt; + } return NULL; + } /* * If this function is called repeatedly, only the first one needs to revalidate. @@ -403,13 +495,13 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid, dm_list_iterate_safe(devh, tmp, &devs) { devl = dm_list_item(devh, struct device_list); - label_read(devl->dev, &label, UINT64_C(0)); + (void) label_read(devl->dev, &label, UINT64_C(0)); dm_list_del(&devl->list); dm_free(devl); } /* If vginfo changed, caller needs to rescan */ - if (!(vginfo = vginfo_from_vgname(vgname, vgid_found)) || + if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid_found)) || strncmp(vginfo->vgid, vgid_found, ID_LEN)) return NULL; @@ -417,7 +509,7 @@ out: return vginfo->fmt; } -struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid) +struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid) { struct lvmcache_vginfo *vginfo; char id[ID_LEN + 1] __attribute__((aligned(8))); @@ -435,12 +527,12 @@ struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid) return vginfo; } -const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid) +const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid) { struct lvmcache_vginfo *vginfo; const char *vgname = NULL; - if ((vginfo = vginfo_from_vgid(vgid))) + if ((vginfo = lvmcache_vginfo_from_vgid(vgid))) vgname = vginfo->vgname; if (mem && vgname) @@ -461,7 +553,7 @@ static int _info_is_valid(struct lvmcache_info *info) * So if the VG appears to be unlocked here, it should be safe * to use the cached value. */ - if (info->vginfo && !vgname_is_locked(info->vginfo->vgname)) + if (info->vginfo && !lvmcache_vgname_is_locked(info->vginfo->vgname)) return 1; if (!(info->status & CACHE_LOCKED)) @@ -498,7 +590,7 @@ static int _vginfo_is_invalid(struct lvmcache_vginfo *vginfo) * If valid_only is set, data will only be returned if the cached data is * known still to be valid. */ -struct lvmcache_info *info_from_pvid(const char *pvid, int valid_only) +struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, int valid_only) { struct lvmcache_info *info; char id[ID_LEN + 1] __attribute__((aligned(8))); @@ -518,17 +610,24 @@ struct lvmcache_info *info_from_pvid(const char *pvid, int valid_only) return info; } +const char *lvmcache_vgname_from_info(struct lvmcache_info *info) +{ + if (info->vginfo) + return info->vginfo->vgname; + return NULL; +} + char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid) { struct lvmcache_info *info; char *vgname; - if (!device_from_pvid(cmd, (const struct id *)pvid, NULL)) { + if (!lvmcache_device_from_pvid(cmd, (const struct id *)pvid, NULL, NULL)) { log_error("Couldn't find device with uuid %s.", pvid); return NULL; } - info = info_from_pvid(pvid, 0); + info = lvmcache_info_from_pvid(pvid, 0); if (!info) return_NULL; @@ -544,7 +643,7 @@ static void _rescan_entry(struct lvmcache_info *info) struct label *label; if (info->status & CACHE_INVALID) - label_read(info->dev, &label, UINT64_C(0)); + (void) label_read(info->dev, &label, UINT64_C(0)); } static int _scan_invalid(void) @@ -563,6 +662,9 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan) int r = 0; + if (lvmetad_active()) + return 1; + /* Avoid recursion when a PVID can't be found! */ if (_scanning_in_progress) return 0; @@ -579,18 +681,16 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan) goto out; } - if (full_scan == 2 && !cmd->filter->use_count && !refresh_filters(cmd)) { - log_error("refresh filters failed"); - goto out; - } + if (full_scan == 2 && (cmd->filter && !cmd->filter->use_count) && !refresh_filters(cmd)) + goto_out; - if (!(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1 : 0))) { + if (!cmd->filter || !(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1 : 0))) { log_error("dev_iter creation failed"); goto out; } while ((dev = dev_iter_get(iter))) - label_read(dev, &label, UINT64_C(0)); + (void) label_read(dev, &label, UINT64_C(0)); dev_iter_destroy(iter); @@ -617,13 +717,29 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan) return r; } -struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted) +struct volume_group *lvmcache_get_vg(struct cmd_context *cmd, const char *vgname, + const char *vgid, unsigned precommitted) { struct lvmcache_vginfo *vginfo; - struct volume_group *vg; + struct volume_group *vg = NULL; struct format_instance *fid; + struct format_instance_ctx fic; + + /* + * We currently do not store precommitted metadata in lvmetad at + * all. This means that any request for precommitted metadata is served + * using the classic scanning mechanics, and read from disk or from + * lvmcache. + */ + if (lvmetad_active() && !precommitted) { + /* Still serve the locally cached VG if available */ + if (vgid && (vginfo = lvmcache_vginfo_from_vgid(vgid)) && + vginfo->vgmetadata && (vg = vginfo->cached_vg)) + goto out; + return lvmetad_vg_lookup(cmd, vgname, vgid); + } - if (!vgid || !(vginfo = vginfo_from_vgid(vgid)) || !vginfo->vgmetadata) + if (!vgid || !(vginfo = lvmcache_vginfo_from_vgid(vgid)) || !vginfo->vgmetadata) return NULL; if (!_vginfo_is_valid(vginfo)) @@ -642,32 +758,84 @@ struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted) * Note that we do not clear the PRECOMMITTED flag. */ if ((precommitted && !vginfo->precommitted) || - (!precommitted && vginfo->precommitted && !memlock())) + (!precommitted && vginfo->precommitted && !critical_section())) return NULL; - if (!(fid = vginfo->fmt->ops->create_instance(vginfo->fmt, - vginfo->vgname, - vgid, NULL))) - return_NULL; + /* Use already-cached VG struct when available */ + if ((vg = vginfo->cached_vg)) + goto out; - if (!(vg = import_vg_from_buffer(vginfo->vgmetadata, fid))) { - _free_cached_vgmetadata(vginfo); - free_vg(vg); + fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS; + fic.context.vg_ref.vg_name = vginfo->vgname; + fic.context.vg_ref.vg_id = vgid; + if (!(fid = vginfo->fmt->ops->create_instance(vginfo->fmt, &fic))) return_NULL; - } - log_debug("Using cached %smetadata for VG %s.", - vginfo->precommitted ? "pre-committed" : "", vginfo->vgname); + /* Build config tree from vgmetadata, if not yet cached */ + if (!vginfo->cft && + !(vginfo->cft = + dm_config_from_string(vginfo->vgmetadata))) + goto_bad; + + if (!(vg = import_vg_from_config_tree(vginfo->cft, fid))) + goto_bad; + + /* Cache VG struct for reuse */ + vginfo->cached_vg = vg; + vginfo->holders = 1; + vginfo->vg_use_count = 0; + vg->vginfo = vginfo; + + if (!dm_pool_lock(vg->vgmem, detect_internal_vg_cache_corruption())) + goto_bad; + +out: + vginfo->holders++; + vginfo->vg_use_count++; + log_debug("Using cached %smetadata for VG %s with %u holder(s).", + vginfo->precommitted ? "pre-committed " : "", + vginfo->vgname, vginfo->holders); return vg; + +bad: + _free_cached_vgmetadata(vginfo); + return NULL; } +// #if 0 +int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo) +{ + log_debug("VG %s decrementing %d holder(s) at %p.", + vginfo->cached_vg->name, vginfo->holders, vginfo->cached_vg); + + if (--vginfo->holders) + return 0; + + if (vginfo->vg_use_count > 1) + log_debug("VG %s reused %d times.", + vginfo->cached_vg->name, vginfo->vg_use_count); + + /* Debug perform crc check only when it's been used more then once */ + if (!dm_pool_unlock(vginfo->cached_vg->vgmem, + detect_internal_vg_cache_corruption() && + (vginfo->vg_use_count > 1))) + stack; + + vginfo->cached_vg->vginfo = NULL; + vginfo->cached_vg = NULL; + + return 1; +} +// #endif + struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd, int include_internal) { struct dm_list *vgids; struct lvmcache_vginfo *vginfo; + // TODO plug into lvmetad here automagically? lvmcache_label_scan(cmd, 0); if (!(vgids = str_list_create(cmd->mem))) { @@ -728,7 +896,7 @@ struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname, return NULL; } - if (!(vginfo = vginfo_from_vgname(vgname, vgid))) + if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) return pvids; dm_list_iterate_items(info, &vginfo->infos) { @@ -742,33 +910,49 @@ struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname, return pvids; } -struct device *device_from_pvid(struct cmd_context *cmd, const struct id *pvid, - unsigned *scan_done_once) +static struct device *_device_from_pvid(const struct id *pvid, + uint64_t *label_sector) { - struct label *label; struct lvmcache_info *info; + struct label *label; + + if ((info = lvmcache_info_from_pvid((const char *) pvid, 0))) { + if (lvmetad_active()) { + if (info->label && label_sector) + *label_sector = info->label->sector; + return info->dev; + } - /* Already cached ? */ - if ((info = info_from_pvid((const char *) pvid, 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 (id_equal(pvid, (struct id *) &info->dev->pvid)) { + if (label_sector) + *label_sector = label->sector; return info->dev; + } } } + return NULL; +} + +struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid, + unsigned *scan_done_once, uint64_t *label_sector) +{ + struct device *dev; + + /* Already cached ? */ + dev = _device_from_pvid(pvid, label_sector); + if (dev) + return dev; lvmcache_label_scan(cmd, 0); /* Try again */ - if ((info = info_from_pvid((const char *) pvid, 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)) - return info->dev; - } - } + dev = _device_from_pvid(pvid, label_sector); + if (dev) + return dev; - if (memlock() || (scan_done_once && *scan_done_once)) + if (critical_section() || (scan_done_once && *scan_done_once)) return NULL; lvmcache_label_scan(cmd, 2); @@ -776,18 +960,14 @@ struct device *device_from_pvid(struct cmd_context *cmd, const struct id *pvid, *scan_done_once = 1; /* Try again */ - if ((info = info_from_pvid((const char *) pvid, 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)) - return info->dev; - } - } + dev = _device_from_pvid(pvid, label_sector); + if (dev) + return dev; return NULL; } -const char *pvid_from_devname(struct cmd_context *cmd, +const char *lvmcache_pvid_from_devname(struct cmd_context *cmd, const char *devname) { struct device *dev; @@ -813,7 +993,7 @@ static int _free_vginfo(struct lvmcache_vginfo *vginfo) _free_cached_vgmetadata(vginfo); - vginfo2 = primary_vginfo = vginfo_from_vgname(vginfo->vgname, NULL); + vginfo2 = primary_vginfo = lvmcache_vginfo_from_vgname(vginfo->vgname, NULL); if (vginfo == primary_vginfo) { dm_hash_remove(_vgname_hash, vginfo->vgname); @@ -823,21 +1003,20 @@ static int _free_vginfo(struct lvmcache_vginfo *vginfo) vginfo->vgname); r = 0; } - } else do - if (vginfo2->next == vginfo) { - vginfo2->next = vginfo->next; - break; + } else + while (vginfo2) { + if (vginfo2->next == vginfo) { + vginfo2->next = vginfo->next; + break; + } + vginfo2 = vginfo2->next; } - while ((vginfo2 = primary_vginfo->next)); - if (vginfo->vgname) - dm_free(vginfo->vgname); - - if (vginfo->creation_host) - dm_free(vginfo->creation_host); + dm_free(vginfo->vgname); + dm_free(vginfo->creation_host); if (*vginfo->vgid && _vgid_hash && - vginfo_from_vgid(vginfo->vgid) == vginfo) + lvmcache_vginfo_from_vgid(vginfo->vgid) == vginfo) dm_hash_remove(_vgid_hash, vginfo->vgid); dm_list_del(&vginfo->list); @@ -886,6 +1065,7 @@ static int _lvmcache_update_pvid(struct lvmcache_info *info, const char *pvid) /* * Nothing to do if already stored with same pvid. */ + if (((dm_hash_lookup(_pvid_hash, pvid)) == info) && !strcmp(info->dev->pvid, pvid)) return 1; @@ -914,6 +1094,7 @@ static int _lvmcache_update_vgid(struct lvmcache_info *info, if (vginfo && *vginfo->vgid) dm_hash_remove(_vgid_hash, vginfo->vgid); if (!vgid) { + /* FIXME: unreachable code path */ log_debug("lvmcache: %s: clearing VGID", info ? dev_name(info->dev) : vginfo->vgname); return 1; } @@ -928,8 +1109,8 @@ static int _lvmcache_update_vgid(struct lvmcache_info *info, if (!is_orphan_vg(vginfo->vgname)) log_debug("lvmcache: %s: setting %s VGID to %s", - dev_name(info->dev), vginfo->vgname, - vginfo->vgid); + (info) ? dev_name(info->dev) : "", + vginfo->vgname, vginfo->vgid); return 1; } @@ -1036,7 +1217,7 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info, _drop_vginfo(info, info->vginfo); /* Get existing vginfo or create new one */ - if (!(vginfo = vginfo_from_vgname(vgname, vgid))) { + if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) { /*** FIXME - vginfo ends up duplicated instead of renamed. // Renaming? This lookup fails. if ((vginfo = vginfo_from_vgid(vgid))) { @@ -1088,18 +1269,18 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info, * If we're scanning and there's an invalidated entry, remove it. * Otherwise we risk bogus warnings of duplicate VGs. */ - while ((primary_vginfo = vginfo_from_vgname(vgname, NULL)) && - _scanning_in_progress && _vginfo_is_invalid(primary_vginfo)) + while ((primary_vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)) && + _scanning_in_progress && _vginfo_is_invalid(primary_vginfo)) { + orphan_vginfo = lvmcache_vginfo_from_vgname(primary_vginfo->fmt->orphan_vg_name, NULL); + if (!orphan_vginfo) { + log_error(INTERNAL_ERROR "Orphan vginfo %s lost from cache.", + primary_vginfo->fmt->orphan_vg_name); + dm_free(vginfo->vgname); + dm_free(vginfo); + return 0; + } dm_list_iterate_items_safe(info2, info3, &primary_vginfo->infos) { - orphan_vginfo = vginfo_from_vgname(primary_vginfo->fmt->orphan_vg_name, NULL); - if (!orphan_vginfo) { - log_error(INTERNAL_ERROR "Orphan vginfo %s lost from cache.", - primary_vginfo->fmt->orphan_vg_name); - dm_free(vginfo->vgname); - dm_free(vginfo); - return 0; - } - _drop_vginfo(info2, primary_vginfo); + _vginfo_detach_info(info2); _vginfo_attach_info(orphan_vginfo, info2); if (info2->mdas.n) sprintf(mdabuf, " with %u mdas", @@ -1111,6 +1292,10 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info, vgname, orphan_vginfo->vgid[0] ? " (" : "", orphan_vginfo->vgid[0] ? orphan_vginfo->vgid : "", orphan_vginfo->vgid[0] ? ")" : "", mdabuf); + } + + if (!_drop_vginfo(NULL, primary_vginfo)) + return_0; } if (!_insert_vginfo(vginfo, vgid, vgstatus, creation_host, @@ -1134,7 +1319,7 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info, else if (!_lvmcache_update_vgid(NULL, vginfo, vgid)) /* Orphans */ return_0; - _update_cache_vginfo_lock_state(vginfo, vgname_is_locked(vgname)); + _update_cache_vginfo_lock_state(vginfo, lvmcache_vgname_is_locked(vgname)); /* FIXME Check consistency of list! */ vginfo->fmt = fmt; @@ -1211,10 +1396,14 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, vgid = vgname; } + /* When using lvmetad, the PV could not have become orphaned. */ + if (lvmetad_active() && is_orphan_vg(vgname) && info->vginfo) + return 1; + /* If PV without mdas is already in a real VG, don't make it orphan */ if (is_orphan_vg(vgname) && info->vginfo && mdas_empty_or_ignored(&info->mdas) && - !is_orphan_vg(info->vginfo->vgname) && memlock()) + !is_orphan_vg(info->vginfo->vgname) && critical_section()) return 1; /* If moving PV from orphan to real VG, always mark it valid */ @@ -1241,7 +1430,7 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted) dm_list_iterate_items(pvl, &vg->pvs) { strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1); /* FIXME Could pvl->pv->dev->pvid ever be different? */ - if ((info = info_from_pvid(pvid_s, 0)) && + if ((info = lvmcache_info_from_pvid(pvid_s, 0)) && !lvmcache_update_vgname_and_id(info, vg->name, (char *) &vg->id, vg->status, NULL)) @@ -1269,11 +1458,11 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid, return NULL; } - strncpy(pvid_s, pvid, sizeof(pvid_s)); + strncpy(pvid_s, pvid, sizeof(pvid_s) - 1); pvid_s[sizeof(pvid_s) - 1] = '\0'; - if (!(existing = info_from_pvid(pvid_s, 0)) && - !(existing = info_from_pvid(dev->pvid, 0))) { + if (!(existing = lvmcache_info_from_pvid(pvid_s, 0)) && + !(existing = lvmcache_info_from_pvid(dev->pvid, 0))) { if (!(label = label_create(labeller))) return_NULL; if (!(info = dm_zalloc(sizeof(*info)))) { @@ -1286,6 +1475,9 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid, info->label = label; dm_list_init(&info->list); info->dev = dev; + + lvmcache_del_mdas(info); + lvmcache_del_das(info); } else { if (existing->dev != dev) { /* Is the existing entry a duplicate pvid e.g. md ? */ @@ -1440,5 +1632,266 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans) dm_list_init(&_vginfos); if (retain_orphans) - init_lvmcache_orphans(cmd); + if (!init_lvmcache_orphans(cmd)) + stack; +} + +int lvmcache_pvid_is_locked(const char *pvid) { + struct lvmcache_info *info; + info = lvmcache_info_from_pvid(pvid, 0); + if (!info || !info->vginfo) + return 0; + + return lvmcache_vgname_is_locked(info->vginfo->vgname); +} + +int lvmcache_fid_add_mdas(struct lvmcache_info *info, struct format_instance *fid, + const char *id, int id_len) +{ + return fid_add_mdas(fid, &info->mdas, id, id_len); +} + +int lvmcache_fid_add_mdas_pv(struct lvmcache_info *info, struct format_instance *fid) +{ + return lvmcache_fid_add_mdas(info, fid, info->dev->pvid, ID_LEN); +} + +int lvmcache_fid_add_mdas_vg(struct lvmcache_vginfo *vginfo, struct format_instance *fid) +{ + struct lvmcache_info *info; + dm_list_iterate_items(info, &vginfo->infos) { + if (!lvmcache_fid_add_mdas_pv(info, fid)) + return_0; + } + return 1; +} + +static int _get_pv_if_in_vg(struct lvmcache_info *info, + struct physical_volume *pv) +{ + char vgname[NAME_LEN + 1]; + char vgid[ID_LEN + 1]; + + if (info->vginfo && info->vginfo->vgname && + !is_orphan_vg(info->vginfo->vgname)) { + /* + * get_pv_from_vg_by_id() may call + * lvmcache_label_scan() and drop cached + * vginfo so make a local copy of string. + */ + strcpy(vgname, info->vginfo->vgname); + memcpy(vgid, info->vginfo->vgid, sizeof(vgid)); + + if (get_pv_from_vg_by_id(info->fmt, vgname, vgid, + info->dev->pvid, pv)) + return 1; + } + + return 0; +} + +int lvmcache_populate_pv_fields(struct lvmcache_info *info, + struct physical_volume *pv, + int scan_label_only) +{ + struct data_area_list *da; + + /* Have we already cached vgname? */ + if (!scan_label_only && _get_pv_if_in_vg(info, pv)) + return 1; + + /* Perform full scan (just the first time) and try again */ + if (!scan_label_only && !critical_section() && !full_scan_done()) { + lvmcache_label_scan(info->fmt->cmd, 2); + + if (_get_pv_if_in_vg(info, pv)) + return 1; + } + + /* Orphan */ + pv->dev = info->dev; + pv->fmt = info->fmt; + pv->size = info->device_size >> SECTOR_SHIFT; + pv->vg_name = FMT_TEXT_ORPHAN_VG_NAME; + memcpy(&pv->id, &info->dev->pvid, sizeof(pv->id)); + + /* Currently only support exactly one data area */ + if (dm_list_size(&info->das) != 1) { + log_error("Must be exactly one data area (found %d) on PV %s", + dm_list_size(&info->das), dev_name(info->dev)); + return 0; + } + + dm_list_iterate_items(da, &info->das) + pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT; + + return 1; +} + +int lvmcache_check_format(struct lvmcache_info *info, const struct format_type *fmt) +{ + if (info->fmt != fmt) { + log_error("PV %s is a different format (seqno %s)", + dev_name(info->dev), info->fmt->name); + return 0; + } + return 1; +} + +void lvmcache_del_mdas(struct lvmcache_info *info) +{ + if (info->mdas.n) + del_mdas(&info->mdas); + dm_list_init(&info->mdas); +} + +void lvmcache_del_das(struct lvmcache_info *info) +{ + if (info->das.n) + del_das(&info->das); + dm_list_init(&info->das); +} + +int lvmcache_add_mda(struct lvmcache_info *info, struct device *dev, + uint64_t start, uint64_t size, unsigned ignored) +{ + return add_mda(info->fmt, NULL, &info->mdas, dev, start, size, ignored); +} + +int lvmcache_add_da(struct lvmcache_info *info, uint64_t start, uint64_t size) +{ + return add_da(NULL, &info->das, start, size); +} + + +void lvmcache_update_pv(struct lvmcache_info *info, struct physical_volume *pv, + const struct format_type *fmt) +{ + info->device_size = pv->size << SECTOR_SHIFT; + info->fmt = fmt; +} + +int lvmcache_update_das(struct lvmcache_info *info, struct physical_volume *pv) +{ + struct data_area_list *da; + if (info->das.n) { + if (!pv->pe_start) + dm_list_iterate_items(da, &info->das) + pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT; + del_das(&info->das); + } else + dm_list_init(&info->das); + + if (!add_da(NULL, &info->das, pv->pe_start << SECTOR_SHIFT, 0 /*pv->size << SECTOR_SHIFT*/)) + return_0; + + return 1; +} + +int lvmcache_foreach_pv(struct lvmcache_vginfo *vginfo, + int (*fun)(struct lvmcache_info *, void *), + void *baton) +{ + struct lvmcache_info *info; + dm_list_iterate_items(info, &vginfo->infos) { + if (!fun(info, baton)) + return_0; + } + + return 1; +} + +int lvmcache_foreach_mda(struct lvmcache_info *info, + int (*fun)(struct metadata_area *, void *), + void *baton) +{ + struct metadata_area *mda; + dm_list_iterate_items(mda, &info->mdas) { + if (!fun(mda, baton)) + return_0; + } + + return 1; +} + +int lvmcache_mda_count(struct lvmcache_info *info) +{ + return dm_list_size(&info->mdas); +} + +int lvmcache_foreach_da(struct lvmcache_info *info, + int (*fun)(struct disk_locn *, void *), + void *baton) +{ + struct data_area_list *da; + dm_list_iterate_items(da, &info->das) { + if (!fun(&da->disk_locn, baton)) + return_0; + } + + return 1; +} + +/* + * The lifetime of the label returned is tied to the lifetime of the + * lvmcache_info which is the same as lvmcache itself. + */ +struct label *lvmcache_get_label(struct lvmcache_info *info) { + return info->label; +} + +void lvmcache_make_valid(struct lvmcache_info *info) { + info->status &= ~CACHE_INVALID; +} + +uint64_t lvmcache_device_size(struct lvmcache_info *info) { + return info->device_size; +} + +void lvmcache_set_device_size(struct lvmcache_info *info, uint64_t size) { + info->device_size = size; +} + +struct device *lvmcache_device(struct lvmcache_info *info) { + return info->dev; +} + +int lvmcache_is_orphan(struct lvmcache_info *info) { + if (!info->vginfo) + return 1; /* FIXME? */ + return is_orphan_vg(info->vginfo->vgname); +} + +int lvmcache_vgid_is_cached(const char *vgid) { + struct lvmcache_vginfo *vginfo; + + if (lvmetad_active()) + return 1; + + vginfo = lvmcache_vginfo_from_vgid(vgid); + + if (!vginfo || !vginfo->vgname) + return 0; + + if (is_orphan_vg(vginfo->vgname)) + return 0; + + return 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. + */ +int lvmcache_uncertain_ownership(struct lvmcache_info *info) { + return mdas_empty_or_ignored(&info->mdas); +} + +int lvmcache_smallest_mda_size(struct lvmcache_info *info) +{ + return find_min_mda_size(&info->mdas); +} + +const struct format_type *lvmcache_fmt(struct lvmcache_info *info) { + return info->fmt; } |