From 962b2a559dde931e5e519706b755bf2764b8338a Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Tue, 29 Jan 2008 23:45:48 +0000 Subject: [PATCH] Rely upon internally-cached PV labels while corresponding VG lock is held. --- WHATS_NEW | 1 + lib/cache/lvmcache.c | 74 +++++++++++++++++++++++++++++++---- lib/cache/lvmcache.h | 2 +- lib/device/dev-io.c | 2 +- lib/format_text/archiver.c | 2 +- lib/format_text/format-text.c | 4 +- lib/label/label.c | 13 ++++-- lib/report/report.c | 4 +- 8 files changed, 83 insertions(+), 19 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index e4e392fe7..5daf18e25 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.33 - =================================== + Rely upon internally-cached PV labels while corresponding VG lock is held. Version 2.02.32 - 29th January 2008 =================================== diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c index 7ceac094b..63e7c37ea 100644 --- a/lib/cache/lvmcache.c +++ b/lib/cache/lvmcache.c @@ -49,6 +49,41 @@ int lvmcache_init(void) return 1; } +static void _update_cache_info_lock_state(struct lvmcache_info *info, int locked) +{ + int was_locked = (info->status & CACHE_LOCKED) ? 1 : 0; + + /* + * Cache becomes invalid whenever lock state changes + */ + if (was_locked != locked) + info->status |= CACHE_INVALID; + + if (locked) + info->status |= CACHE_LOCKED; + else + info->status &= ~CACHE_LOCKED; +} + +static void _update_cache_vginfo_lock_state(struct lvmcache_vginfo *vginfo, + int locked) +{ + struct lvmcache_info *info; + + list_iterate_items(info, &vginfo->infos) + _update_cache_info_lock_state(info, locked); +} + +static void _update_cache_lock_state(const char *vgname, int locked) +{ + struct lvmcache_vginfo *vginfo; + + if (!(vginfo = vginfo_from_vgname(vgname, NULL))) + return; + + _update_cache_vginfo_lock_state(vginfo, locked); +} + void lvmcache_lock_vgname(const char *vgname, int read_only __attribute((unused))) { if (!_lock_hash && !lvmcache_init()) { @@ -59,6 +94,8 @@ void lvmcache_lock_vgname(const char *vgname, int read_only __attribute((unused) if (!dm_hash_insert(_lock_hash, vgname, (void *) 1)) log_error("Cache locking failure for %s", vgname); + _update_cache_lock_state(vgname, 1); + _vgs_locked++; } @@ -72,7 +109,8 @@ int vgname_is_locked(const char *vgname) void lvmcache_unlock_vgname(const char *vgname) { - /* FIXME: Clear all CACHE_LOCKED flags in this vg */ + _update_cache_lock_state(vgname, 0); + dm_hash_remove(_lock_hash, vgname); /* FIXME Do this per-VG */ @@ -182,7 +220,22 @@ const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid) return vgname; } -struct lvmcache_info *info_from_pvid(const char *pvid) +static int _info_is_valid(struct lvmcache_info *info) +{ + if (info->status & CACHE_INVALID) + return 0; + + if (!(info->status & CACHE_LOCKED)) + return 0; + + return 1; +} + +/* + * 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 *info; char id[ID_LEN + 1] __attribute((aligned(8))); @@ -196,6 +249,9 @@ struct lvmcache_info *info_from_pvid(const char *pvid) if (!(info = dm_hash_lookup(_pvid_hash, id))) return NULL; + if (valid_only && !_info_is_valid(info)) + return NULL; + return info; } @@ -344,7 +400,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid) struct lvmcache_info *info; /* Already cached ? */ - if ((info = info_from_pvid((char *) pvid))) { + if ((info = info_from_pvid((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)) @@ -355,7 +411,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid) lvmcache_label_scan(cmd, 0); /* Try again */ - if ((info = info_from_pvid((char *) pvid))) { + if ((info = info_from_pvid((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)) @@ -369,7 +425,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid) lvmcache_label_scan(cmd, 2); /* Try again */ - if ((info = info_from_pvid((char *) pvid))) { + if ((info = info_from_pvid((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)) @@ -645,6 +701,8 @@ static int _lvmcache_update_vgname(struct lvmcache_info *info, info->vginfo = vginfo; list_add(&vginfo->infos, &info->list); + _update_cache_vginfo_lock_state(vginfo, vgname_is_locked(vgname)); + /* FIXME Check consistency of list! */ vginfo->fmt = info->fmt; @@ -716,7 +774,7 @@ int lvmcache_update_vg(struct volume_group *vg) 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)) && + if ((info = info_from_pvid(pvid_s, 0)) && !lvmcache_update_vgname_and_id(info, vg->name, (char *) &vg->id, vg->status, NULL)) @@ -743,8 +801,8 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid, strncpy(pvid_s, pvid, sizeof(pvid_s)); pvid_s[sizeof(pvid_s) - 1] = '\0'; - if (!(existing = info_from_pvid(pvid_s)) && - !(existing = info_from_pvid(dev->pvid))) { + if (!(existing = info_from_pvid(pvid_s, 0)) && + !(existing = info_from_pvid(dev->pvid, 0))) { if (!(label = label_create(labeller))) { stack; return NULL; diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h index 43b4ae3be..bdda2f0a4 100644 --- a/lib/cache/lvmcache.h +++ b/lib/cache/lvmcache.h @@ -86,7 +86,7 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid); struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname, const char *vgid); struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid); -struct lvmcache_info *info_from_pvid(const char *pvid); +struct lvmcache_info *info_from_pvid(const char *pvid, int valid_only); const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid); struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid); int vgs_locked(void); diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c index 54ae88e58..b2b476726 100644 --- a/lib/device/dev-io.c +++ b/lib/device/dev-io.c @@ -523,7 +523,7 @@ static int _dev_close(struct device *dev, int immediate) /* Close unless device is known to belong to a locked VG */ if (immediate || (dev->open_count < 1 && - (!(info = info_from_pvid(dev->pvid)) || + (!(info = info_from_pvid(dev->pvid, 0)) || !info->vginfo || !vgname_is_locked(info->vginfo->vgname)))) _close(dev); diff --git a/lib/format_text/archiver.c b/lib/format_text/archiver.c index 9aa803b04..c736727ec 100644 --- a/lib/format_text/archiver.c +++ b/lib/format_text/archiver.c @@ -305,7 +305,7 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg) /* Add any metadata areas on the PVs */ list_iterate_items(pvl, &vg->pvs) { pv = pvl->pv; - if (!(info = info_from_pvid(pv->dev->pvid))) { + if (!(info = info_from_pvid(pv->dev->pvid, 0))) { log_error("PV %s missing from cache", pv_dev_name(pv)); return 0; diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c index c83d7a821..0783c1416 100644 --- a/lib/format_text/format-text.c +++ b/lib/format_text/format-text.c @@ -391,7 +391,7 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area, } error: - if ((info = info_from_pvid(dev_area->dev->pvid))) + if ((info = info_from_pvid(dev_area->dev->pvid, 0))) lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN, 0, NULL); return NULL; @@ -1610,7 +1610,7 @@ static int _text_pv_setup(const struct format_type *fmt, /* If new vg, add any further mdas on this PV to the fid's mda list */ if (vg) { /* Iterate through all mdas on this PV */ - if ((info = info_from_pvid(pv->dev->pvid))) { + if ((info = info_from_pvid(pv->dev->pvid, 0))) { pvmdas = &info->mdas; list_iterate_items(mda, pvmdas) { mda_count++; diff --git a/lib/label/label.c b/lib/label/label.c index f08dfe30b..e0454d015 100644 --- a/lib/label/label.c +++ b/lib/label/label.c @@ -179,7 +179,7 @@ static struct labeller *_find_labeller(struct device *dev, char *buf, out: if (!found) { - if ((info = info_from_pvid(dev->pvid))) + if ((info = info_from_pvid(dev->pvid, 0))) lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN, 0, NULL); log_very_verbose("%s: No label detected", dev_name(dev)); @@ -260,7 +260,6 @@ int label_remove(struct device *dev) return r; } -/* FIXME Avoid repeated re-reading if cache lock held */ int label_read(struct device *dev, struct label **result, uint64_t scan_sector) { @@ -270,10 +269,16 @@ int label_read(struct device *dev, struct label **result, struct lvmcache_info *info; int r = 0; + if ((info = info_from_pvid(dev->pvid, 1))) { + log_debug("Using cached label for %s", dev_name(dev)); + *result = info->label; + return 1; + } + if (!dev_open(dev)) { stack; - if ((info = info_from_pvid(dev->pvid))) + if ((info = info_from_pvid(dev->pvid, 0))) lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN, 0, NULL); @@ -353,7 +358,7 @@ int label_verify(struct device *dev) int r = 0; if (!dev_open(dev)) { - if ((info = info_from_pvid(dev->pvid))) + if ((info = info_from_pvid(dev->pvid, 0))) lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN, 0, NULL); diff --git a/lib/report/report.c b/lib/report/report.c index af73259a5..291e223de 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -840,7 +840,7 @@ static int _pvmdas_disp(struct dm_report *rh, struct dm_pool *mem, uint32_t count; const char *pvid = (const char *)(&((struct id *) data)->uuid); - info = info_from_pvid(pvid); + info = info_from_pvid(pvid, 0); count = info ? list_size(&info->mdas) : 0; return _uint32_disp(rh, mem, field, &count, private); @@ -867,7 +867,7 @@ static int _pvmdafree_disp(struct dm_report *rh, struct dm_pool *mem, const char *pvid = (const char *)(&((struct id *) data)->uuid); struct metadata_area *mda; - info = info_from_pvid(pvid); + info = info_from_pvid(pvid, 0); list_iterate_items(mda, &info->mdas) { if (!mda->ops->mda_free_sectors) -- 2.43.5