1*7c604eeaShaad /* $NetBSD: lvmcache.c,v 1.1.1.3 2009/12/02 00:26:21 haad Exp $ */
256a34939Shaad
356a34939Shaad /*
456a34939Shaad * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
556a34939Shaad * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
656a34939Shaad *
756a34939Shaad * This file is part of LVM2.
856a34939Shaad *
956a34939Shaad * This copyrighted material is made available to anyone wishing to use,
1056a34939Shaad * modify, copy, or redistribute it subject to the terms and conditions
1156a34939Shaad * of the GNU Lesser General Public License v.2.1.
1256a34939Shaad *
1356a34939Shaad * You should have received a copy of the GNU Lesser General Public License
1456a34939Shaad * along with this program; if not, write to the Free Software Foundation,
1556a34939Shaad * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1656a34939Shaad */
1756a34939Shaad
1856a34939Shaad #include "lib.h"
1956a34939Shaad #include "lvmcache.h"
2056a34939Shaad #include "toolcontext.h"
2156a34939Shaad #include "dev-cache.h"
2256a34939Shaad #include "locking.h"
2356a34939Shaad #include "metadata.h"
2456a34939Shaad #include "filter.h"
25*7c604eeaShaad #include "filter-persistent.h"
2656a34939Shaad #include "memlock.h"
2756a34939Shaad #include "str_list.h"
2856a34939Shaad #include "format-text.h"
2956a34939Shaad #include "format_pool.h"
3056a34939Shaad #include "format1.h"
3156a34939Shaad
3256a34939Shaad static struct dm_hash_table *_pvid_hash = NULL;
3356a34939Shaad static struct dm_hash_table *_vgid_hash = NULL;
3456a34939Shaad static struct dm_hash_table *_vgname_hash = NULL;
3556a34939Shaad static struct dm_hash_table *_lock_hash = NULL;
3656a34939Shaad static struct dm_list _vginfos;
3756a34939Shaad static int _scanning_in_progress = 0;
3856a34939Shaad static int _has_scanned = 0;
3956a34939Shaad static int _vgs_locked = 0;
4056a34939Shaad static int _vg_global_lock_held = 0; /* Global lock held when cache wiped? */
4156a34939Shaad
lvmcache_init(void)4256a34939Shaad int lvmcache_init(void)
4356a34939Shaad {
4456a34939Shaad dm_list_init(&_vginfos);
4556a34939Shaad
4656a34939Shaad if (!(_vgname_hash = dm_hash_create(128)))
4756a34939Shaad return 0;
4856a34939Shaad
4956a34939Shaad if (!(_vgid_hash = dm_hash_create(128)))
5056a34939Shaad return 0;
5156a34939Shaad
5256a34939Shaad if (!(_pvid_hash = dm_hash_create(128)))
5356a34939Shaad return 0;
5456a34939Shaad
5556a34939Shaad if (!(_lock_hash = dm_hash_create(128)))
5656a34939Shaad return 0;
5756a34939Shaad
58*7c604eeaShaad /*
59*7c604eeaShaad * Reinitialising the cache clears the internal record of
60*7c604eeaShaad * which locks are held. The global lock can be held during
61*7c604eeaShaad * this operation so its state must be restored afterwards.
62*7c604eeaShaad */
63*7c604eeaShaad if (_vg_global_lock_held) {
6456a34939Shaad lvmcache_lock_vgname(VG_GLOBAL, 0);
65*7c604eeaShaad _vg_global_lock_held = 0;
66*7c604eeaShaad }
6756a34939Shaad
6856a34939Shaad return 1;
6956a34939Shaad }
7056a34939Shaad
7156a34939Shaad /* Volume Group metadata cache functions */
_free_cached_vgmetadata(struct lvmcache_vginfo * vginfo)7256a34939Shaad static void _free_cached_vgmetadata(struct lvmcache_vginfo *vginfo)
7356a34939Shaad {
7456a34939Shaad if (!vginfo || !vginfo->vgmetadata)
7556a34939Shaad return;
7656a34939Shaad
7756a34939Shaad dm_free(vginfo->vgmetadata);
7856a34939Shaad
7956a34939Shaad vginfo->vgmetadata = NULL;
8056a34939Shaad
8156a34939Shaad log_debug("Metadata cache: VG %s wiped.", vginfo->vgname);
8256a34939Shaad }
8356a34939Shaad
84*7c604eeaShaad /*
85*7c604eeaShaad * Cache VG metadata against the vginfo with matching vgid.
86*7c604eeaShaad */
_store_metadata(struct volume_group * vg,unsigned precommitted)87*7c604eeaShaad static void _store_metadata(struct volume_group *vg, unsigned precommitted)
8856a34939Shaad {
89*7c604eeaShaad char uuid[64] __attribute((aligned(8)));
90*7c604eeaShaad struct lvmcache_vginfo *vginfo;
9156a34939Shaad int size;
9256a34939Shaad
93*7c604eeaShaad if (!(vginfo = vginfo_from_vgid((const char *)&vg->id))) {
94*7c604eeaShaad stack;
95*7c604eeaShaad return;
96*7c604eeaShaad }
97*7c604eeaShaad
9856a34939Shaad if (vginfo->vgmetadata)
9956a34939Shaad _free_cached_vgmetadata(vginfo);
10056a34939Shaad
10156a34939Shaad if (!(size = export_vg_to_buffer(vg, &vginfo->vgmetadata))) {
10256a34939Shaad stack;
10356a34939Shaad return;
10456a34939Shaad }
10556a34939Shaad
10656a34939Shaad vginfo->precommitted = precommitted;
10756a34939Shaad
108*7c604eeaShaad if (!id_write_format((const struct id *)vginfo->vgid, uuid, sizeof(uuid))) {
109*7c604eeaShaad stack;
110*7c604eeaShaad return;
111*7c604eeaShaad }
112*7c604eeaShaad
113*7c604eeaShaad log_debug("Metadata cache: VG %s (%s) stored (%d bytes%s).",
114*7c604eeaShaad vginfo->vgname, uuid, size,
115*7c604eeaShaad precommitted ? ", precommitted" : "");
11656a34939Shaad }
11756a34939Shaad
_update_cache_info_lock_state(struct lvmcache_info * info,int locked,int * cached_vgmetadata_valid)11856a34939Shaad static void _update_cache_info_lock_state(struct lvmcache_info *info,
11956a34939Shaad int locked,
12056a34939Shaad int *cached_vgmetadata_valid)
12156a34939Shaad {
12256a34939Shaad int was_locked = (info->status & CACHE_LOCKED) ? 1 : 0;
12356a34939Shaad
12456a34939Shaad /*
12556a34939Shaad * Cache becomes invalid whenever lock state changes unless
12656a34939Shaad * exclusive VG_GLOBAL is held (i.e. while scanning).
12756a34939Shaad */
12856a34939Shaad if (!vgname_is_locked(VG_GLOBAL) && (was_locked != locked)) {
12956a34939Shaad info->status |= CACHE_INVALID;
13056a34939Shaad *cached_vgmetadata_valid = 0;
13156a34939Shaad }
13256a34939Shaad
13356a34939Shaad if (locked)
13456a34939Shaad info->status |= CACHE_LOCKED;
13556a34939Shaad else
13656a34939Shaad info->status &= ~CACHE_LOCKED;
13756a34939Shaad }
13856a34939Shaad
_update_cache_vginfo_lock_state(struct lvmcache_vginfo * vginfo,int locked)13956a34939Shaad static void _update_cache_vginfo_lock_state(struct lvmcache_vginfo *vginfo,
14056a34939Shaad int locked)
14156a34939Shaad {
14256a34939Shaad struct lvmcache_info *info;
14356a34939Shaad int cached_vgmetadata_valid = 1;
14456a34939Shaad
14556a34939Shaad dm_list_iterate_items(info, &vginfo->infos)
14656a34939Shaad _update_cache_info_lock_state(info, locked,
14756a34939Shaad &cached_vgmetadata_valid);
14856a34939Shaad
14956a34939Shaad if (!cached_vgmetadata_valid)
15056a34939Shaad _free_cached_vgmetadata(vginfo);
15156a34939Shaad }
15256a34939Shaad
_update_cache_lock_state(const char * vgname,int locked)15356a34939Shaad static void _update_cache_lock_state(const char *vgname, int locked)
15456a34939Shaad {
15556a34939Shaad struct lvmcache_vginfo *vginfo;
15656a34939Shaad
15756a34939Shaad if (!(vginfo = vginfo_from_vgname(vgname, NULL)))
15856a34939Shaad return;
15956a34939Shaad
16056a34939Shaad _update_cache_vginfo_lock_state(vginfo, locked);
16156a34939Shaad }
16256a34939Shaad
_drop_metadata(const char * vgname)16356a34939Shaad static void _drop_metadata(const char *vgname)
16456a34939Shaad {
16556a34939Shaad struct lvmcache_vginfo *vginfo;
16656a34939Shaad struct lvmcache_info *info;
16756a34939Shaad
16856a34939Shaad if (!(vginfo = vginfo_from_vgname(vgname, NULL)))
16956a34939Shaad return;
17056a34939Shaad
17156a34939Shaad /*
17256a34939Shaad * Invalidate cached PV labels.
17356a34939Shaad * If cached precommitted metadata exists that means we
17456a34939Shaad * already invalidated the PV labels (before caching it)
17556a34939Shaad * and we must not do it again.
17656a34939Shaad */
17756a34939Shaad
17856a34939Shaad if (!vginfo->precommitted)
17956a34939Shaad dm_list_iterate_items(info, &vginfo->infos)
18056a34939Shaad info->status |= CACHE_INVALID;
18156a34939Shaad
18256a34939Shaad _free_cached_vgmetadata(vginfo);
18356a34939Shaad }
18456a34939Shaad
lvmcache_drop_metadata(const char * vgname)18556a34939Shaad void lvmcache_drop_metadata(const char *vgname)
18656a34939Shaad {
18756a34939Shaad /* For VG_ORPHANS, we need to invalidate all labels on orphan PVs. */
18856a34939Shaad if (!strcmp(vgname, VG_ORPHANS)) {
18956a34939Shaad _drop_metadata(FMT_TEXT_ORPHAN_VG_NAME);
19056a34939Shaad _drop_metadata(FMT_LVM1_ORPHAN_VG_NAME);
19156a34939Shaad _drop_metadata(FMT_POOL_ORPHAN_VG_NAME);
19256a34939Shaad
19356a34939Shaad /* Indicate that PVs could now be missing from the cache */
19456a34939Shaad init_full_scan_done(0);
19556a34939Shaad } else if (!vgname_is_locked(VG_GLOBAL))
19656a34939Shaad _drop_metadata(vgname);
19756a34939Shaad }
19856a34939Shaad
199*7c604eeaShaad /*
200*7c604eeaShaad * Ensure vgname2 comes after vgname1 alphabetically.
201*7c604eeaShaad * Special VG names beginning with '#' don't count.
202*7c604eeaShaad */
_vgname_order_correct(const char * vgname1,const char * vgname2)203*7c604eeaShaad static int _vgname_order_correct(const char *vgname1, const char *vgname2)
204*7c604eeaShaad {
205*7c604eeaShaad if ((*vgname1 == '#') || (*vgname2 == '#'))
206*7c604eeaShaad return 1;
207*7c604eeaShaad
208*7c604eeaShaad if (strcmp(vgname1, vgname2) < 0)
209*7c604eeaShaad return 1;
210*7c604eeaShaad
211*7c604eeaShaad return 0;
212*7c604eeaShaad }
213*7c604eeaShaad
214*7c604eeaShaad /*
215*7c604eeaShaad * Ensure VG locks are acquired in alphabetical order.
216*7c604eeaShaad */
lvmcache_verify_lock_order(const char * vgname)217*7c604eeaShaad int lvmcache_verify_lock_order(const char *vgname)
218*7c604eeaShaad {
219*7c604eeaShaad struct dm_hash_node *n;
220*7c604eeaShaad const char *vgname2;
221*7c604eeaShaad
222*7c604eeaShaad if (!_lock_hash)
223*7c604eeaShaad return_0;
224*7c604eeaShaad
225*7c604eeaShaad dm_hash_iterate(n, _lock_hash) {
226*7c604eeaShaad if (!dm_hash_get_data(_lock_hash, n))
227*7c604eeaShaad return_0;
228*7c604eeaShaad
229*7c604eeaShaad vgname2 = dm_hash_get_key(_lock_hash, n);
230*7c604eeaShaad
231*7c604eeaShaad if (!_vgname_order_correct(vgname2, vgname)) {
232*7c604eeaShaad log_errno(EDEADLK, "Internal error: VG lock %s must "
233*7c604eeaShaad "be requested before %s, not after.",
234*7c604eeaShaad vgname, vgname2);
235*7c604eeaShaad return_0;
236*7c604eeaShaad }
237*7c604eeaShaad }
238*7c604eeaShaad
239*7c604eeaShaad return 1;
240*7c604eeaShaad }
241*7c604eeaShaad
lvmcache_lock_vgname(const char * vgname,int read_only __attribute ((unused)))24256a34939Shaad void lvmcache_lock_vgname(const char *vgname, int read_only __attribute((unused)))
24356a34939Shaad {
24456a34939Shaad if (!_lock_hash && !lvmcache_init()) {
24556a34939Shaad log_error("Internal cache initialisation failed");
24656a34939Shaad return;
24756a34939Shaad }
24856a34939Shaad
24956a34939Shaad if (dm_hash_lookup(_lock_hash, vgname))
25056a34939Shaad log_error("Internal error: Nested locking attempted on VG %s.",
25156a34939Shaad vgname);
25256a34939Shaad
25356a34939Shaad if (!dm_hash_insert(_lock_hash, vgname, (void *) 1))
25456a34939Shaad log_error("Cache locking failure for %s", vgname);
25556a34939Shaad
25656a34939Shaad _update_cache_lock_state(vgname, 1);
25756a34939Shaad
25856a34939Shaad if (strcmp(vgname, VG_GLOBAL))
25956a34939Shaad _vgs_locked++;
26056a34939Shaad }
26156a34939Shaad
vgname_is_locked(const char * vgname)26256a34939Shaad int vgname_is_locked(const char *vgname)
26356a34939Shaad {
26456a34939Shaad if (!_lock_hash)
26556a34939Shaad return 0;
26656a34939Shaad
26756a34939Shaad return dm_hash_lookup(_lock_hash, vgname) ? 1 : 0;
26856a34939Shaad }
26956a34939Shaad
lvmcache_unlock_vgname(const char * vgname)27056a34939Shaad void lvmcache_unlock_vgname(const char *vgname)
27156a34939Shaad {
27256a34939Shaad if (!dm_hash_lookup(_lock_hash, vgname))
27356a34939Shaad log_error("Internal error: Attempt to unlock unlocked VG %s.",
27456a34939Shaad vgname);
27556a34939Shaad
27656a34939Shaad _update_cache_lock_state(vgname, 0);
27756a34939Shaad
27856a34939Shaad dm_hash_remove(_lock_hash, vgname);
27956a34939Shaad
28056a34939Shaad /* FIXME Do this per-VG */
28156a34939Shaad if (strcmp(vgname, VG_GLOBAL) && !--_vgs_locked)
28256a34939Shaad dev_close_all();
28356a34939Shaad }
28456a34939Shaad
vgs_locked(void)28556a34939Shaad int vgs_locked(void)
28656a34939Shaad {
28756a34939Shaad return _vgs_locked;
28856a34939Shaad }
28956a34939Shaad
_vginfo_attach_info(struct lvmcache_vginfo * vginfo,struct lvmcache_info * info)29056a34939Shaad static void _vginfo_attach_info(struct lvmcache_vginfo *vginfo,
29156a34939Shaad struct lvmcache_info *info)
29256a34939Shaad {
29356a34939Shaad if (!vginfo)
29456a34939Shaad return;
29556a34939Shaad
29656a34939Shaad info->vginfo = vginfo;
29756a34939Shaad dm_list_add(&vginfo->infos, &info->list);
29856a34939Shaad }
29956a34939Shaad
_vginfo_detach_info(struct lvmcache_info * info)30056a34939Shaad static void _vginfo_detach_info(struct lvmcache_info *info)
30156a34939Shaad {
30256a34939Shaad if (!dm_list_empty(&info->list)) {
30356a34939Shaad dm_list_del(&info->list);
30456a34939Shaad dm_list_init(&info->list);
30556a34939Shaad }
30656a34939Shaad
30756a34939Shaad info->vginfo = NULL;
30856a34939Shaad }
30956a34939Shaad
31056a34939Shaad /* If vgid supplied, require a match. */
vginfo_from_vgname(const char * vgname,const char * vgid)31156a34939Shaad struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname, const char *vgid)
31256a34939Shaad {
31356a34939Shaad struct lvmcache_vginfo *vginfo;
31456a34939Shaad
31556a34939Shaad if (!vgname)
31656a34939Shaad return vginfo_from_vgid(vgid);
31756a34939Shaad
31856a34939Shaad if (!_vgname_hash)
31956a34939Shaad return NULL;
32056a34939Shaad
32156a34939Shaad if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname)))
32256a34939Shaad return NULL;
32356a34939Shaad
32456a34939Shaad if (vgid)
32556a34939Shaad do
32656a34939Shaad if (!strncmp(vgid, vginfo->vgid, ID_LEN))
32756a34939Shaad return vginfo;
32856a34939Shaad while ((vginfo = vginfo->next));
32956a34939Shaad
33056a34939Shaad return vginfo;
33156a34939Shaad }
33256a34939Shaad
fmt_from_vgname(const char * vgname,const char * vgid)33356a34939Shaad const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
33456a34939Shaad {
33556a34939Shaad struct lvmcache_vginfo *vginfo;
33656a34939Shaad struct lvmcache_info *info;
33756a34939Shaad struct label *label;
33856a34939Shaad struct dm_list *devh, *tmp;
33956a34939Shaad struct dm_list devs;
34056a34939Shaad struct device_list *devl;
34156a34939Shaad char vgid_found[ID_LEN + 1] __attribute((aligned(8)));
34256a34939Shaad
34356a34939Shaad if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
34456a34939Shaad return NULL;
34556a34939Shaad
34656a34939Shaad /* This function is normally called before reading metadata so
34756a34939Shaad * we check cached labels here. Unfortunately vginfo is volatile. */
34856a34939Shaad dm_list_init(&devs);
34956a34939Shaad dm_list_iterate_items(info, &vginfo->infos) {
35056a34939Shaad if (!(devl = dm_malloc(sizeof(*devl)))) {
35156a34939Shaad log_error("device_list element allocation failed");
35256a34939Shaad return NULL;
35356a34939Shaad }
35456a34939Shaad devl->dev = info->dev;
35556a34939Shaad dm_list_add(&devs, &devl->list);
35656a34939Shaad }
35756a34939Shaad
35856a34939Shaad memcpy(vgid_found, vginfo->vgid, sizeof(vgid_found));
35956a34939Shaad
36056a34939Shaad dm_list_iterate_safe(devh, tmp, &devs) {
36156a34939Shaad devl = dm_list_item(devh, struct device_list);
36256a34939Shaad label_read(devl->dev, &label, UINT64_C(0));
36356a34939Shaad dm_list_del(&devl->list);
36456a34939Shaad dm_free(devl);
36556a34939Shaad }
36656a34939Shaad
36756a34939Shaad /* If vginfo changed, caller needs to rescan */
36856a34939Shaad if (!(vginfo = vginfo_from_vgname(vgname, vgid_found)) ||
36956a34939Shaad strncmp(vginfo->vgid, vgid_found, ID_LEN))
37056a34939Shaad return NULL;
37156a34939Shaad
37256a34939Shaad return vginfo->fmt;
37356a34939Shaad }
37456a34939Shaad
vginfo_from_vgid(const char * vgid)37556a34939Shaad struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid)
37656a34939Shaad {
37756a34939Shaad struct lvmcache_vginfo *vginfo;
37856a34939Shaad char id[ID_LEN + 1] __attribute((aligned(8)));
37956a34939Shaad
38056a34939Shaad if (!_vgid_hash || !vgid)
38156a34939Shaad return NULL;
38256a34939Shaad
38356a34939Shaad /* vgid not necessarily NULL-terminated */
38456a34939Shaad strncpy(&id[0], vgid, ID_LEN);
38556a34939Shaad id[ID_LEN] = '\0';
38656a34939Shaad
38756a34939Shaad if (!(vginfo = dm_hash_lookup(_vgid_hash, id)))
38856a34939Shaad return NULL;
38956a34939Shaad
39056a34939Shaad return vginfo;
39156a34939Shaad }
39256a34939Shaad
vgname_from_vgid(struct dm_pool * mem,const char * vgid)39356a34939Shaad const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid)
39456a34939Shaad {
39556a34939Shaad struct lvmcache_vginfo *vginfo;
39656a34939Shaad const char *vgname = NULL;
39756a34939Shaad
39856a34939Shaad if ((vginfo = vginfo_from_vgid(vgid)))
39956a34939Shaad vgname = vginfo->vgname;
40056a34939Shaad
40156a34939Shaad if (mem && vgname)
40256a34939Shaad return dm_pool_strdup(mem, vgname);
40356a34939Shaad
40456a34939Shaad return vgname;
40556a34939Shaad }
40656a34939Shaad
_info_is_valid(struct lvmcache_info * info)40756a34939Shaad static int _info_is_valid(struct lvmcache_info *info)
40856a34939Shaad {
40956a34939Shaad if (info->status & CACHE_INVALID)
41056a34939Shaad return 0;
41156a34939Shaad
41256a34939Shaad /*
41356a34939Shaad * The caller must hold the VG lock to manipulate metadata.
41456a34939Shaad * In a cluster, remote nodes sometimes read metadata in the
41556a34939Shaad * knowledge that the controlling node is holding the lock.
41656a34939Shaad * So if the VG appears to be unlocked here, it should be safe
41756a34939Shaad * to use the cached value.
41856a34939Shaad */
41956a34939Shaad if (info->vginfo && !vgname_is_locked(info->vginfo->vgname))
42056a34939Shaad return 1;
42156a34939Shaad
42256a34939Shaad if (!(info->status & CACHE_LOCKED))
42356a34939Shaad return 0;
42456a34939Shaad
42556a34939Shaad return 1;
42656a34939Shaad }
42756a34939Shaad
_vginfo_is_valid(struct lvmcache_vginfo * vginfo)42856a34939Shaad static int _vginfo_is_valid(struct lvmcache_vginfo *vginfo)
42956a34939Shaad {
43056a34939Shaad struct lvmcache_info *info;
43156a34939Shaad
43256a34939Shaad /* Invalid if any info is invalid */
43356a34939Shaad dm_list_iterate_items(info, &vginfo->infos)
43456a34939Shaad if (!_info_is_valid(info))
43556a34939Shaad return 0;
43656a34939Shaad
43756a34939Shaad return 1;
43856a34939Shaad }
43956a34939Shaad
44056a34939Shaad /* vginfo is invalid if it does not contain at least one valid info */
_vginfo_is_invalid(struct lvmcache_vginfo * vginfo)44156a34939Shaad static int _vginfo_is_invalid(struct lvmcache_vginfo *vginfo)
44256a34939Shaad {
44356a34939Shaad struct lvmcache_info *info;
44456a34939Shaad
44556a34939Shaad dm_list_iterate_items(info, &vginfo->infos)
44656a34939Shaad if (_info_is_valid(info))
44756a34939Shaad return 0;
44856a34939Shaad
44956a34939Shaad return 1;
45056a34939Shaad }
45156a34939Shaad
45256a34939Shaad /*
45356a34939Shaad * If valid_only is set, data will only be returned if the cached data is
45456a34939Shaad * known still to be valid.
45556a34939Shaad */
info_from_pvid(const char * pvid,int valid_only)45656a34939Shaad struct lvmcache_info *info_from_pvid(const char *pvid, int valid_only)
45756a34939Shaad {
45856a34939Shaad struct lvmcache_info *info;
45956a34939Shaad char id[ID_LEN + 1] __attribute((aligned(8)));
46056a34939Shaad
46156a34939Shaad if (!_pvid_hash || !pvid)
46256a34939Shaad return NULL;
46356a34939Shaad
46456a34939Shaad strncpy(&id[0], pvid, ID_LEN);
46556a34939Shaad id[ID_LEN] = '\0';
46656a34939Shaad
46756a34939Shaad if (!(info = dm_hash_lookup(_pvid_hash, id)))
46856a34939Shaad return NULL;
46956a34939Shaad
47056a34939Shaad if (valid_only && !_info_is_valid(info))
47156a34939Shaad return NULL;
47256a34939Shaad
47356a34939Shaad return info;
47456a34939Shaad }
47556a34939Shaad
_rescan_entry(struct lvmcache_info * info)47656a34939Shaad static void _rescan_entry(struct lvmcache_info *info)
47756a34939Shaad {
47856a34939Shaad struct label *label;
47956a34939Shaad
48056a34939Shaad if (info->status & CACHE_INVALID)
48156a34939Shaad label_read(info->dev, &label, UINT64_C(0));
48256a34939Shaad }
48356a34939Shaad
_scan_invalid(void)48456a34939Shaad static int _scan_invalid(void)
48556a34939Shaad {
48656a34939Shaad dm_hash_iter(_pvid_hash, (dm_hash_iterate_fn) _rescan_entry);
48756a34939Shaad
48856a34939Shaad return 1;
48956a34939Shaad }
49056a34939Shaad
lvmcache_label_scan(struct cmd_context * cmd,int full_scan)49156a34939Shaad int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
49256a34939Shaad {
49356a34939Shaad struct label *label;
49456a34939Shaad struct dev_iter *iter;
49556a34939Shaad struct device *dev;
49656a34939Shaad struct format_type *fmt;
49756a34939Shaad
49856a34939Shaad int r = 0;
49956a34939Shaad
50056a34939Shaad /* Avoid recursion when a PVID can't be found! */
50156a34939Shaad if (_scanning_in_progress)
50256a34939Shaad return 0;
50356a34939Shaad
50456a34939Shaad _scanning_in_progress = 1;
50556a34939Shaad
50656a34939Shaad if (!_vgname_hash && !lvmcache_init()) {
50756a34939Shaad log_error("Internal cache initialisation failed");
50856a34939Shaad goto out;
50956a34939Shaad }
51056a34939Shaad
51156a34939Shaad if (_has_scanned && !full_scan) {
51256a34939Shaad r = _scan_invalid();
51356a34939Shaad goto out;
51456a34939Shaad }
51556a34939Shaad
516*7c604eeaShaad if (full_scan == 2 && !refresh_filters(cmd)) {
517*7c604eeaShaad log_error("refresh filters failed");
518*7c604eeaShaad goto out;
519*7c604eeaShaad }
520*7c604eeaShaad
52156a34939Shaad if (!(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1 : 0))) {
52256a34939Shaad log_error("dev_iter creation failed");
52356a34939Shaad goto out;
52456a34939Shaad }
52556a34939Shaad
52656a34939Shaad while ((dev = dev_iter_get(iter)))
52756a34939Shaad label_read(dev, &label, UINT64_C(0));
52856a34939Shaad
52956a34939Shaad dev_iter_destroy(iter);
53056a34939Shaad
53156a34939Shaad _has_scanned = 1;
53256a34939Shaad
53356a34939Shaad /* Perform any format-specific scanning e.g. text files */
53456a34939Shaad dm_list_iterate_items(fmt, &cmd->formats) {
53556a34939Shaad if (fmt->ops->scan && !fmt->ops->scan(fmt))
53656a34939Shaad goto out;
53756a34939Shaad }
53856a34939Shaad
539*7c604eeaShaad /*
540*7c604eeaShaad * If we are a long-lived process, write out the updated persistent
541*7c604eeaShaad * device cache for the benefit of short-lived processes.
542*7c604eeaShaad */
543*7c604eeaShaad if (full_scan == 2 && cmd->is_long_lived && cmd->dump_filter)
544*7c604eeaShaad persistent_filter_dump(cmd->filter);
545*7c604eeaShaad
54656a34939Shaad r = 1;
54756a34939Shaad
54856a34939Shaad out:
54956a34939Shaad _scanning_in_progress = 0;
55056a34939Shaad
55156a34939Shaad return r;
55256a34939Shaad }
55356a34939Shaad
lvmcache_get_vg(const char * vgid,unsigned precommitted)55456a34939Shaad struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted)
55556a34939Shaad {
55656a34939Shaad struct lvmcache_vginfo *vginfo;
55756a34939Shaad struct volume_group *vg;
55856a34939Shaad struct format_instance *fid;
55956a34939Shaad
56056a34939Shaad if (!vgid || !(vginfo = vginfo_from_vgid(vgid)) || !vginfo->vgmetadata)
56156a34939Shaad return NULL;
56256a34939Shaad
56356a34939Shaad if (!_vginfo_is_valid(vginfo))
56456a34939Shaad return NULL;
56556a34939Shaad
56656a34939Shaad /*
56756a34939Shaad * Don't return cached data if either:
56856a34939Shaad * (i) precommitted metadata is requested but we don't have it cached
56956a34939Shaad * - caller should read it off disk;
57056a34939Shaad * (ii) live metadata is requested but we have precommitted metadata cached
57156a34939Shaad * and no devices are suspended so caller may read it off disk.
57256a34939Shaad *
57356a34939Shaad * If live metadata is requested but we have precommitted metadata cached
57456a34939Shaad * and devices are suspended, we assume this precommitted metadata has
57556a34939Shaad * already been preloaded and committed so it's OK to return it as live.
57656a34939Shaad * Note that we do not clear the PRECOMMITTED flag.
57756a34939Shaad */
57856a34939Shaad if ((precommitted && !vginfo->precommitted) ||
57956a34939Shaad (!precommitted && vginfo->precommitted && !memlock()))
58056a34939Shaad return NULL;
58156a34939Shaad
58256a34939Shaad if (!(fid = vginfo->fmt->ops->create_instance(vginfo->fmt,
58356a34939Shaad vginfo->vgname,
58456a34939Shaad vgid, NULL)))
58556a34939Shaad return_NULL;
58656a34939Shaad
58756a34939Shaad if (!(vg = import_vg_from_buffer(vginfo->vgmetadata, fid)) ||
58856a34939Shaad !vg_validate(vg)) {
58956a34939Shaad _free_cached_vgmetadata(vginfo);
590*7c604eeaShaad vg_release(vg);
59156a34939Shaad return_NULL;
59256a34939Shaad }
59356a34939Shaad
59456a34939Shaad log_debug("Using cached %smetadata for VG %s.",
59556a34939Shaad vginfo->precommitted ? "pre-committed" : "", vginfo->vgname);
59656a34939Shaad
59756a34939Shaad return vg;
59856a34939Shaad }
59956a34939Shaad
lvmcache_get_vgids(struct cmd_context * cmd,int full_scan)60056a34939Shaad struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd, int full_scan)
60156a34939Shaad {
60256a34939Shaad struct dm_list *vgids;
60356a34939Shaad struct lvmcache_vginfo *vginfo;
60456a34939Shaad
60556a34939Shaad lvmcache_label_scan(cmd, full_scan);
60656a34939Shaad
60756a34939Shaad if (!(vgids = str_list_create(cmd->mem))) {
60856a34939Shaad log_error("vgids list allocation failed");
60956a34939Shaad return NULL;
61056a34939Shaad }
61156a34939Shaad
61256a34939Shaad dm_list_iterate_items(vginfo, &_vginfos) {
61356a34939Shaad if (!str_list_add(cmd->mem, vgids,
61456a34939Shaad dm_pool_strdup(cmd->mem, vginfo->vgid))) {
61556a34939Shaad log_error("strlist allocation failed");
61656a34939Shaad return NULL;
61756a34939Shaad }
61856a34939Shaad }
61956a34939Shaad
62056a34939Shaad return vgids;
62156a34939Shaad }
62256a34939Shaad
lvmcache_get_vgnames(struct cmd_context * cmd,int full_scan)62356a34939Shaad struct dm_list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan)
62456a34939Shaad {
62556a34939Shaad struct dm_list *vgnames;
62656a34939Shaad struct lvmcache_vginfo *vginfo;
62756a34939Shaad
62856a34939Shaad lvmcache_label_scan(cmd, full_scan);
62956a34939Shaad
63056a34939Shaad if (!(vgnames = str_list_create(cmd->mem))) {
631*7c604eeaShaad log_errno(ENOMEM, "vgnames list allocation failed");
63256a34939Shaad return NULL;
63356a34939Shaad }
63456a34939Shaad
63556a34939Shaad dm_list_iterate_items(vginfo, &_vginfos) {
63656a34939Shaad if (!str_list_add(cmd->mem, vgnames,
63756a34939Shaad dm_pool_strdup(cmd->mem, vginfo->vgname))) {
638*7c604eeaShaad log_errno(ENOMEM, "strlist allocation failed");
63956a34939Shaad return NULL;
64056a34939Shaad }
64156a34939Shaad }
64256a34939Shaad
64356a34939Shaad return vgnames;
64456a34939Shaad }
64556a34939Shaad
lvmcache_get_pvids(struct cmd_context * cmd,const char * vgname,const char * vgid)64656a34939Shaad struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
64756a34939Shaad const char *vgid)
64856a34939Shaad {
64956a34939Shaad struct dm_list *pvids;
65056a34939Shaad struct lvmcache_vginfo *vginfo;
65156a34939Shaad struct lvmcache_info *info;
65256a34939Shaad
65356a34939Shaad if (!(pvids = str_list_create(cmd->mem))) {
65456a34939Shaad log_error("pvids list allocation failed");
65556a34939Shaad return NULL;
65656a34939Shaad }
65756a34939Shaad
65856a34939Shaad if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
65956a34939Shaad return pvids;
66056a34939Shaad
66156a34939Shaad dm_list_iterate_items(info, &vginfo->infos) {
66256a34939Shaad if (!str_list_add(cmd->mem, pvids,
66356a34939Shaad dm_pool_strdup(cmd->mem, info->dev->pvid))) {
66456a34939Shaad log_error("strlist allocation failed");
66556a34939Shaad return NULL;
66656a34939Shaad }
66756a34939Shaad }
66856a34939Shaad
66956a34939Shaad return pvids;
67056a34939Shaad }
67156a34939Shaad
device_from_pvid(struct cmd_context * cmd,struct id * pvid)67256a34939Shaad struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
67356a34939Shaad {
67456a34939Shaad struct label *label;
67556a34939Shaad struct lvmcache_info *info;
67656a34939Shaad
67756a34939Shaad /* Already cached ? */
67856a34939Shaad if ((info = info_from_pvid((char *) pvid, 0))) {
67956a34939Shaad if (label_read(info->dev, &label, UINT64_C(0))) {
68056a34939Shaad info = (struct lvmcache_info *) label->info;
68156a34939Shaad if (id_equal(pvid, (struct id *) &info->dev->pvid))
68256a34939Shaad return info->dev;
68356a34939Shaad }
68456a34939Shaad }
68556a34939Shaad
68656a34939Shaad lvmcache_label_scan(cmd, 0);
68756a34939Shaad
68856a34939Shaad /* Try again */
68956a34939Shaad if ((info = info_from_pvid((char *) pvid, 0))) {
69056a34939Shaad if (label_read(info->dev, &label, UINT64_C(0))) {
69156a34939Shaad info = (struct lvmcache_info *) label->info;
69256a34939Shaad if (id_equal(pvid, (struct id *) &info->dev->pvid))
69356a34939Shaad return info->dev;
69456a34939Shaad }
69556a34939Shaad }
69656a34939Shaad
69756a34939Shaad if (memlock())
69856a34939Shaad return NULL;
69956a34939Shaad
70056a34939Shaad lvmcache_label_scan(cmd, 2);
70156a34939Shaad
70256a34939Shaad /* Try again */
70356a34939Shaad if ((info = info_from_pvid((char *) pvid, 0))) {
70456a34939Shaad if (label_read(info->dev, &label, UINT64_C(0))) {
70556a34939Shaad info = (struct lvmcache_info *) label->info;
70656a34939Shaad if (id_equal(pvid, (struct id *) &info->dev->pvid))
70756a34939Shaad return info->dev;
70856a34939Shaad }
70956a34939Shaad }
71056a34939Shaad
71156a34939Shaad return NULL;
71256a34939Shaad }
71356a34939Shaad
_free_vginfo(struct lvmcache_vginfo * vginfo)71456a34939Shaad static int _free_vginfo(struct lvmcache_vginfo *vginfo)
71556a34939Shaad {
71656a34939Shaad struct lvmcache_vginfo *primary_vginfo, *vginfo2;
71756a34939Shaad int r = 1;
71856a34939Shaad
71956a34939Shaad _free_cached_vgmetadata(vginfo);
72056a34939Shaad
72156a34939Shaad vginfo2 = primary_vginfo = vginfo_from_vgname(vginfo->vgname, NULL);
72256a34939Shaad
72356a34939Shaad if (vginfo == primary_vginfo) {
72456a34939Shaad dm_hash_remove(_vgname_hash, vginfo->vgname);
72556a34939Shaad if (vginfo->next && !dm_hash_insert(_vgname_hash, vginfo->vgname,
72656a34939Shaad vginfo->next)) {
72756a34939Shaad log_error("_vgname_hash re-insertion for %s failed",
72856a34939Shaad vginfo->vgname);
72956a34939Shaad r = 0;
73056a34939Shaad }
73156a34939Shaad } else do
73256a34939Shaad if (vginfo2->next == vginfo) {
73356a34939Shaad vginfo2->next = vginfo->next;
73456a34939Shaad break;
73556a34939Shaad }
73656a34939Shaad while ((vginfo2 = primary_vginfo->next));
73756a34939Shaad
73856a34939Shaad if (vginfo->vgname)
73956a34939Shaad dm_free(vginfo->vgname);
74056a34939Shaad
74156a34939Shaad if (vginfo->creation_host)
74256a34939Shaad dm_free(vginfo->creation_host);
74356a34939Shaad
74456a34939Shaad if (*vginfo->vgid && _vgid_hash &&
74556a34939Shaad vginfo_from_vgid(vginfo->vgid) == vginfo)
74656a34939Shaad dm_hash_remove(_vgid_hash, vginfo->vgid);
74756a34939Shaad
74856a34939Shaad dm_list_del(&vginfo->list);
74956a34939Shaad
75056a34939Shaad dm_free(vginfo);
75156a34939Shaad
75256a34939Shaad return r;
75356a34939Shaad }
75456a34939Shaad
75556a34939Shaad /*
75656a34939Shaad * vginfo must be info->vginfo unless info is NULL
75756a34939Shaad */
_drop_vginfo(struct lvmcache_info * info,struct lvmcache_vginfo * vginfo)75856a34939Shaad static int _drop_vginfo(struct lvmcache_info *info, struct lvmcache_vginfo *vginfo)
75956a34939Shaad {
76056a34939Shaad if (info)
76156a34939Shaad _vginfo_detach_info(info);
76256a34939Shaad
76356a34939Shaad /* vginfo still referenced? */
76456a34939Shaad if (!vginfo || is_orphan_vg(vginfo->vgname) ||
76556a34939Shaad !dm_list_empty(&vginfo->infos))
76656a34939Shaad return 1;
76756a34939Shaad
76856a34939Shaad if (!_free_vginfo(vginfo))
76956a34939Shaad return_0;
77056a34939Shaad
77156a34939Shaad return 1;
77256a34939Shaad }
77356a34939Shaad
77456a34939Shaad /* Unused
77556a34939Shaad void lvmcache_del(struct lvmcache_info *info)
77656a34939Shaad {
77756a34939Shaad if (info->dev->pvid[0] && _pvid_hash)
77856a34939Shaad dm_hash_remove(_pvid_hash, info->dev->pvid);
77956a34939Shaad
78056a34939Shaad _drop_vginfo(info, info->vginfo);
78156a34939Shaad
78256a34939Shaad info->label->labeller->ops->destroy_label(info->label->labeller,
78356a34939Shaad info->label);
78456a34939Shaad dm_free(info);
78556a34939Shaad
78656a34939Shaad return;
78756a34939Shaad } */
78856a34939Shaad
_lvmcache_update_pvid(struct lvmcache_info * info,const char * pvid)78956a34939Shaad static int _lvmcache_update_pvid(struct lvmcache_info *info, const char *pvid)
79056a34939Shaad {
791bec4d750Shaad /*
792bec4d750Shaad * Nothing to do if already stored with same pvid.
793bec4d750Shaad */
794bec4d750Shaad if (((dm_hash_lookup(_pvid_hash, pvid)) == info) &&
795bec4d750Shaad !strcmp(info->dev->pvid, pvid))
79656a34939Shaad return 1;
797bec4d750Shaad if (*info->dev->pvid)
79856a34939Shaad dm_hash_remove(_pvid_hash, info->dev->pvid);
79956a34939Shaad strncpy(info->dev->pvid, pvid, sizeof(info->dev->pvid));
80056a34939Shaad if (!dm_hash_insert(_pvid_hash, pvid, info)) {
80156a34939Shaad log_error("_lvmcache_update: pvid insertion failed: %s", pvid);
80256a34939Shaad return 0;
80356a34939Shaad }
80456a34939Shaad
80556a34939Shaad return 1;
80656a34939Shaad }
80756a34939Shaad
80856a34939Shaad /*
80956a34939Shaad * vginfo must be info->vginfo unless info is NULL (orphans)
81056a34939Shaad */
_lvmcache_update_vgid(struct lvmcache_info * info,struct lvmcache_vginfo * vginfo,const char * vgid)81156a34939Shaad static int _lvmcache_update_vgid(struct lvmcache_info *info,
81256a34939Shaad struct lvmcache_vginfo *vginfo,
81356a34939Shaad const char *vgid)
81456a34939Shaad {
81556a34939Shaad if (!vgid || !vginfo ||
81656a34939Shaad !strncmp(vginfo->vgid, vgid, ID_LEN))
81756a34939Shaad return 1;
81856a34939Shaad
81956a34939Shaad if (vginfo && *vginfo->vgid)
82056a34939Shaad dm_hash_remove(_vgid_hash, vginfo->vgid);
82156a34939Shaad if (!vgid) {
82256a34939Shaad log_debug("lvmcache: %s: clearing VGID", info ? dev_name(info->dev) : vginfo->vgname);
82356a34939Shaad return 1;
82456a34939Shaad }
82556a34939Shaad
82656a34939Shaad strncpy(vginfo->vgid, vgid, ID_LEN);
82756a34939Shaad vginfo->vgid[ID_LEN] = '\0';
82856a34939Shaad if (!dm_hash_insert(_vgid_hash, vginfo->vgid, vginfo)) {
82956a34939Shaad log_error("_lvmcache_update: vgid hash insertion failed: %s",
83056a34939Shaad vginfo->vgid);
83156a34939Shaad return 0;
83256a34939Shaad }
83356a34939Shaad
83456a34939Shaad if (!is_orphan_vg(vginfo->vgname))
83556a34939Shaad log_debug("lvmcache: %s: setting %s VGID to %s",
83656a34939Shaad dev_name(info->dev), vginfo->vgname,
83756a34939Shaad vginfo->vgid);
83856a34939Shaad
83956a34939Shaad return 1;
84056a34939Shaad }
84156a34939Shaad
_insert_vginfo(struct lvmcache_vginfo * new_vginfo,const char * vgid,uint32_t vgstatus,const char * creation_host,struct lvmcache_vginfo * primary_vginfo)84256a34939Shaad static int _insert_vginfo(struct lvmcache_vginfo *new_vginfo, const char *vgid,
84356a34939Shaad uint32_t vgstatus, const char *creation_host,
84456a34939Shaad struct lvmcache_vginfo *primary_vginfo)
84556a34939Shaad {
84656a34939Shaad struct lvmcache_vginfo *last_vginfo = primary_vginfo;
84756a34939Shaad char uuid_primary[64] __attribute((aligned(8)));
84856a34939Shaad char uuid_new[64] __attribute((aligned(8)));
84956a34939Shaad int use_new = 0;
85056a34939Shaad
85156a34939Shaad /* Pre-existing VG takes precedence. Unexported VG takes precedence. */
85256a34939Shaad if (primary_vginfo) {
85356a34939Shaad if (!id_write_format((const struct id *)vgid, uuid_new, sizeof(uuid_new)))
85456a34939Shaad return_0;
85556a34939Shaad
85656a34939Shaad if (!id_write_format((const struct id *)&primary_vginfo->vgid, uuid_primary,
85756a34939Shaad sizeof(uuid_primary)))
85856a34939Shaad return_0;
85956a34939Shaad
86056a34939Shaad /*
86156a34939Shaad * If Primary not exported, new exported => keep
86256a34939Shaad * Else Primary exported, new not exported => change
86356a34939Shaad * Else Primary has hostname for this machine => keep
86456a34939Shaad * Else Primary has no hostname, new has one => change
86556a34939Shaad * Else New has hostname for this machine => change
86656a34939Shaad * Else Keep primary.
86756a34939Shaad */
86856a34939Shaad if (!(primary_vginfo->status & EXPORTED_VG) &&
86956a34939Shaad (vgstatus & EXPORTED_VG))
87056a34939Shaad log_error("WARNING: Duplicate VG name %s: "
87156a34939Shaad "Existing %s takes precedence over "
87256a34939Shaad "exported %s", new_vginfo->vgname,
87356a34939Shaad uuid_primary, uuid_new);
87456a34939Shaad else if ((primary_vginfo->status & EXPORTED_VG) &&
87556a34939Shaad !(vgstatus & EXPORTED_VG)) {
87656a34939Shaad log_error("WARNING: Duplicate VG name %s: "
87756a34939Shaad "%s takes precedence over exported %s",
87856a34939Shaad new_vginfo->vgname, uuid_new,
87956a34939Shaad uuid_primary);
88056a34939Shaad use_new = 1;
88156a34939Shaad } else if (primary_vginfo->creation_host &&
88256a34939Shaad !strcmp(primary_vginfo->creation_host,
88356a34939Shaad primary_vginfo->fmt->cmd->hostname))
88456a34939Shaad log_error("WARNING: Duplicate VG name %s: "
88556a34939Shaad "Existing %s (created here) takes precedence "
88656a34939Shaad "over %s", new_vginfo->vgname, uuid_primary,
88756a34939Shaad uuid_new);
88856a34939Shaad else if (!primary_vginfo->creation_host && creation_host) {
88956a34939Shaad log_error("WARNING: Duplicate VG name %s: "
89056a34939Shaad "%s (with creation_host) takes precedence over %s",
89156a34939Shaad new_vginfo->vgname, uuid_new,
89256a34939Shaad uuid_primary);
89356a34939Shaad use_new = 1;
89456a34939Shaad } else if (creation_host &&
89556a34939Shaad !strcmp(creation_host,
89656a34939Shaad primary_vginfo->fmt->cmd->hostname)) {
89756a34939Shaad log_error("WARNING: Duplicate VG name %s: "
89856a34939Shaad "%s (created here) takes precedence over %s",
89956a34939Shaad new_vginfo->vgname, uuid_new,
90056a34939Shaad uuid_primary);
90156a34939Shaad use_new = 1;
90256a34939Shaad }
90356a34939Shaad
90456a34939Shaad if (!use_new) {
90556a34939Shaad while (last_vginfo->next)
90656a34939Shaad last_vginfo = last_vginfo->next;
90756a34939Shaad last_vginfo->next = new_vginfo;
90856a34939Shaad return 1;
90956a34939Shaad }
91056a34939Shaad
91156a34939Shaad dm_hash_remove(_vgname_hash, primary_vginfo->vgname);
91256a34939Shaad }
91356a34939Shaad
91456a34939Shaad if (!dm_hash_insert(_vgname_hash, new_vginfo->vgname, new_vginfo)) {
91556a34939Shaad log_error("cache_update: vg hash insertion failed: %s",
91656a34939Shaad new_vginfo->vgname);
91756a34939Shaad return 0;
91856a34939Shaad }
91956a34939Shaad
92056a34939Shaad if (primary_vginfo)
92156a34939Shaad new_vginfo->next = primary_vginfo;
92256a34939Shaad
92356a34939Shaad return 1;
92456a34939Shaad }
92556a34939Shaad
_lvmcache_update_vgname(struct lvmcache_info * info,const char * vgname,const char * vgid,uint32_t vgstatus,const char * creation_host,const struct format_type * fmt)92656a34939Shaad static int _lvmcache_update_vgname(struct lvmcache_info *info,
92756a34939Shaad const char *vgname, const char *vgid,
92856a34939Shaad uint32_t vgstatus, const char *creation_host,
92956a34939Shaad const struct format_type *fmt)
93056a34939Shaad {
93156a34939Shaad struct lvmcache_vginfo *vginfo, *primary_vginfo, *orphan_vginfo;
93256a34939Shaad struct lvmcache_info *info2, *info3;
93356a34939Shaad char mdabuf[32];
93456a34939Shaad // struct lvmcache_vginfo *old_vginfo, *next;
93556a34939Shaad
93656a34939Shaad if (!vgname || (info && info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
93756a34939Shaad return 1;
93856a34939Shaad
93956a34939Shaad /* Remove existing vginfo entry */
94056a34939Shaad if (info)
94156a34939Shaad _drop_vginfo(info, info->vginfo);
94256a34939Shaad
94356a34939Shaad /* Get existing vginfo or create new one */
94456a34939Shaad if (!(vginfo = vginfo_from_vgname(vgname, vgid))) {
94556a34939Shaad /*** FIXME - vginfo ends up duplicated instead of renamed.
94656a34939Shaad // Renaming? This lookup fails.
94756a34939Shaad if ((vginfo = vginfo_from_vgid(vgid))) {
94856a34939Shaad next = vginfo->next;
94956a34939Shaad old_vginfo = vginfo_from_vgname(vginfo->vgname, NULL);
95056a34939Shaad if (old_vginfo == vginfo) {
95156a34939Shaad dm_hash_remove(_vgname_hash, old_vginfo->vgname);
95256a34939Shaad if (old_vginfo->next) {
95356a34939Shaad if (!dm_hash_insert(_vgname_hash, old_vginfo->vgname, old_vginfo->next)) {
95456a34939Shaad log_error("vg hash re-insertion failed: %s",
95556a34939Shaad old_vginfo->vgname);
95656a34939Shaad return 0;
95756a34939Shaad }
95856a34939Shaad }
95956a34939Shaad } else do {
96056a34939Shaad if (old_vginfo->next == vginfo) {
96156a34939Shaad old_vginfo->next = vginfo->next;
96256a34939Shaad break;
96356a34939Shaad }
96456a34939Shaad } while ((old_vginfo = old_vginfo->next));
96556a34939Shaad vginfo->next = NULL;
96656a34939Shaad
96756a34939Shaad dm_free(vginfo->vgname);
96856a34939Shaad if (!(vginfo->vgname = dm_strdup(vgname))) {
96956a34939Shaad log_error("cache vgname alloc failed for %s", vgname);
97056a34939Shaad return 0;
97156a34939Shaad }
97256a34939Shaad
97356a34939Shaad // Rename so can assume new name does not already exist
97456a34939Shaad if (!dm_hash_insert(_vgname_hash, vginfo->vgname, vginfo->next)) {
97556a34939Shaad log_error("vg hash re-insertion failed: %s",
97656a34939Shaad vginfo->vgname);
97756a34939Shaad return 0;
97856a34939Shaad }
97956a34939Shaad } else {
98056a34939Shaad ***/
98156a34939Shaad if (!(vginfo = dm_malloc(sizeof(*vginfo)))) {
98256a34939Shaad log_error("lvmcache_update_vgname: list alloc failed");
98356a34939Shaad return 0;
98456a34939Shaad }
98556a34939Shaad memset(vginfo, 0, sizeof(*vginfo));
98656a34939Shaad if (!(vginfo->vgname = dm_strdup(vgname))) {
98756a34939Shaad dm_free(vginfo);
98856a34939Shaad log_error("cache vgname alloc failed for %s", vgname);
98956a34939Shaad return 0;
99056a34939Shaad }
99156a34939Shaad dm_list_init(&vginfo->infos);
99256a34939Shaad
99356a34939Shaad /*
99456a34939Shaad * If we're scanning and there's an invalidated entry, remove it.
99556a34939Shaad * Otherwise we risk bogus warnings of duplicate VGs.
99656a34939Shaad */
99756a34939Shaad while ((primary_vginfo = vginfo_from_vgname(vgname, NULL)) &&
99856a34939Shaad _scanning_in_progress && _vginfo_is_invalid(primary_vginfo))
99956a34939Shaad dm_list_iterate_items_safe(info2, info3, &primary_vginfo->infos) {
100056a34939Shaad orphan_vginfo = vginfo_from_vgname(primary_vginfo->fmt->orphan_vg_name, NULL);
100156a34939Shaad _drop_vginfo(info2, primary_vginfo);
100256a34939Shaad _vginfo_attach_info(orphan_vginfo, info2);
100356a34939Shaad if (info2->mdas.n)
100456a34939Shaad sprintf(mdabuf, " with %u mdas",
100556a34939Shaad dm_list_size(&info2->mdas));
100656a34939Shaad else
100756a34939Shaad mdabuf[0] = '\0';
100856a34939Shaad log_debug("lvmcache: %s: now in VG %s%s%s%s%s",
100956a34939Shaad dev_name(info2->dev),
101056a34939Shaad vgname, orphan_vginfo->vgid[0] ? " (" : "",
101156a34939Shaad orphan_vginfo->vgid[0] ? orphan_vginfo->vgid : "",
101256a34939Shaad orphan_vginfo->vgid[0] ? ")" : "", mdabuf);
101356a34939Shaad }
101456a34939Shaad
101556a34939Shaad if (!_insert_vginfo(vginfo, vgid, vgstatus, creation_host,
101656a34939Shaad primary_vginfo)) {
101756a34939Shaad dm_free(vginfo->vgname);
101856a34939Shaad dm_free(vginfo);
101956a34939Shaad return 0;
102056a34939Shaad }
102156a34939Shaad /* Ensure orphans appear last on list_iterate */
102256a34939Shaad if (is_orphan_vg(vgname))
102356a34939Shaad dm_list_add(&_vginfos, &vginfo->list);
102456a34939Shaad else
102556a34939Shaad dm_list_add_h(&_vginfos, &vginfo->list);
102656a34939Shaad /***
102756a34939Shaad }
102856a34939Shaad ***/
102956a34939Shaad }
103056a34939Shaad
103156a34939Shaad if (info)
103256a34939Shaad _vginfo_attach_info(vginfo, info);
103356a34939Shaad else if (!_lvmcache_update_vgid(NULL, vginfo, vgid)) /* Orphans */
103456a34939Shaad return_0;
103556a34939Shaad
103656a34939Shaad _update_cache_vginfo_lock_state(vginfo, vgname_is_locked(vgname));
103756a34939Shaad
103856a34939Shaad /* FIXME Check consistency of list! */
103956a34939Shaad vginfo->fmt = fmt;
104056a34939Shaad
104156a34939Shaad if (info) {
104256a34939Shaad if (info->mdas.n)
104356a34939Shaad sprintf(mdabuf, " with %u mdas", dm_list_size(&info->mdas));
104456a34939Shaad else
104556a34939Shaad mdabuf[0] = '\0';
104656a34939Shaad log_debug("lvmcache: %s: now in VG %s%s%s%s%s",
104756a34939Shaad dev_name(info->dev),
104856a34939Shaad vgname, vginfo->vgid[0] ? " (" : "",
104956a34939Shaad vginfo->vgid[0] ? vginfo->vgid : "",
105056a34939Shaad vginfo->vgid[0] ? ")" : "", mdabuf);
105156a34939Shaad } else
105256a34939Shaad log_debug("lvmcache: initialised VG %s", vgname);
105356a34939Shaad
105456a34939Shaad return 1;
105556a34939Shaad }
105656a34939Shaad
_lvmcache_update_vgstatus(struct lvmcache_info * info,uint32_t vgstatus,const char * creation_host)105756a34939Shaad static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstatus,
105856a34939Shaad const char *creation_host)
105956a34939Shaad {
106056a34939Shaad if (!info || !info->vginfo)
106156a34939Shaad return 1;
106256a34939Shaad
106356a34939Shaad if ((info->vginfo->status & EXPORTED_VG) != (vgstatus & EXPORTED_VG))
106456a34939Shaad log_debug("lvmcache: %s: VG %s %s exported",
106556a34939Shaad dev_name(info->dev), info->vginfo->vgname,
106656a34939Shaad vgstatus & EXPORTED_VG ? "now" : "no longer");
106756a34939Shaad
106856a34939Shaad info->vginfo->status = vgstatus;
106956a34939Shaad
107056a34939Shaad if (!creation_host)
107156a34939Shaad return 1;
107256a34939Shaad
107356a34939Shaad if (info->vginfo->creation_host && !strcmp(creation_host,
107456a34939Shaad info->vginfo->creation_host))
107556a34939Shaad return 1;
107656a34939Shaad
107756a34939Shaad if (info->vginfo->creation_host)
107856a34939Shaad dm_free(info->vginfo->creation_host);
107956a34939Shaad
108056a34939Shaad if (!(info->vginfo->creation_host = dm_strdup(creation_host))) {
108156a34939Shaad log_error("cache creation host alloc failed for %s",
108256a34939Shaad creation_host);
108356a34939Shaad return 0;
108456a34939Shaad }
108556a34939Shaad
108656a34939Shaad log_debug("lvmcache: %s: VG %s: Set creation host to %s.",
108756a34939Shaad dev_name(info->dev), info->vginfo->vgname, creation_host);
108856a34939Shaad
108956a34939Shaad return 1;
109056a34939Shaad }
109156a34939Shaad
lvmcache_add_orphan_vginfo(const char * vgname,struct format_type * fmt)109256a34939Shaad int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt)
109356a34939Shaad {
109456a34939Shaad if (!_lock_hash && !lvmcache_init()) {
109556a34939Shaad log_error("Internal cache initialisation failed");
109656a34939Shaad return 0;
109756a34939Shaad }
109856a34939Shaad
109956a34939Shaad return _lvmcache_update_vgname(NULL, vgname, vgname, 0, "", fmt);
110056a34939Shaad }
110156a34939Shaad
lvmcache_update_vgname_and_id(struct lvmcache_info * info,const char * vgname,const char * vgid,uint32_t vgstatus,const char * creation_host)110256a34939Shaad int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
110356a34939Shaad const char *vgname, const char *vgid,
110456a34939Shaad uint32_t vgstatus, const char *creation_host)
110556a34939Shaad {
110656a34939Shaad if (!vgname && !info->vginfo) {
110756a34939Shaad log_error("Internal error: NULL vgname handed to cache");
110856a34939Shaad /* FIXME Remove this */
110956a34939Shaad vgname = info->fmt->orphan_vg_name;
111056a34939Shaad vgid = vgname;
111156a34939Shaad }
111256a34939Shaad
111356a34939Shaad /* If PV without mdas is already in a real VG, don't make it orphan */
111456a34939Shaad if (is_orphan_vg(vgname) && info->vginfo && !dm_list_size(&info->mdas) &&
111556a34939Shaad !is_orphan_vg(info->vginfo->vgname) && memlock())
111656a34939Shaad return 1;
111756a34939Shaad
111856a34939Shaad /* If moving PV from orphan to real VG, always mark it valid */
111956a34939Shaad if (!is_orphan_vg(vgname))
112056a34939Shaad info->status &= ~CACHE_INVALID;
112156a34939Shaad
112256a34939Shaad if (!_lvmcache_update_vgname(info, vgname, vgid, vgstatus,
112356a34939Shaad creation_host, info->fmt) ||
112456a34939Shaad !_lvmcache_update_vgid(info, info->vginfo, vgid) ||
112556a34939Shaad !_lvmcache_update_vgstatus(info, vgstatus, creation_host))
112656a34939Shaad return_0;
112756a34939Shaad
112856a34939Shaad return 1;
112956a34939Shaad }
113056a34939Shaad
lvmcache_update_vg(struct volume_group * vg,unsigned precommitted)113156a34939Shaad int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
113256a34939Shaad {
113356a34939Shaad struct pv_list *pvl;
113456a34939Shaad struct lvmcache_info *info;
113556a34939Shaad char pvid_s[ID_LEN + 1] __attribute((aligned(8)));
113656a34939Shaad
113756a34939Shaad pvid_s[sizeof(pvid_s) - 1] = '\0';
113856a34939Shaad
113956a34939Shaad dm_list_iterate_items(pvl, &vg->pvs) {
114056a34939Shaad strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1);
114156a34939Shaad /* FIXME Could pvl->pv->dev->pvid ever be different? */
114256a34939Shaad if ((info = info_from_pvid(pvid_s, 0)) &&
114356a34939Shaad !lvmcache_update_vgname_and_id(info, vg->name,
114456a34939Shaad (char *) &vg->id,
114556a34939Shaad vg->status, NULL))
114656a34939Shaad return_0;
114756a34939Shaad }
114856a34939Shaad
114956a34939Shaad /* store text representation of vg to cache */
1150*7c604eeaShaad if (vg->cmd->current_settings.cache_vgmetadata)
1151*7c604eeaShaad _store_metadata(vg, precommitted);
115256a34939Shaad
115356a34939Shaad return 1;
115456a34939Shaad }
115556a34939Shaad
lvmcache_add(struct labeller * labeller,const char * pvid,struct device * dev,const char * vgname,const char * vgid,uint32_t vgstatus)115656a34939Shaad struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
115756a34939Shaad struct device *dev,
115856a34939Shaad const char *vgname, const char *vgid,
115956a34939Shaad uint32_t vgstatus)
116056a34939Shaad {
116156a34939Shaad struct label *label;
116256a34939Shaad struct lvmcache_info *existing, *info;
116356a34939Shaad char pvid_s[ID_LEN + 1] __attribute((aligned(8)));
116456a34939Shaad
116556a34939Shaad if (!_vgname_hash && !lvmcache_init()) {
116656a34939Shaad log_error("Internal cache initialisation failed");
116756a34939Shaad return NULL;
116856a34939Shaad }
116956a34939Shaad
117056a34939Shaad strncpy(pvid_s, pvid, sizeof(pvid_s));
117156a34939Shaad pvid_s[sizeof(pvid_s) - 1] = '\0';
117256a34939Shaad
117356a34939Shaad if (!(existing = info_from_pvid(pvid_s, 0)) &&
117456a34939Shaad !(existing = info_from_pvid(dev->pvid, 0))) {
117556a34939Shaad if (!(label = label_create(labeller)))
117656a34939Shaad return_NULL;
117756a34939Shaad if (!(info = dm_malloc(sizeof(*info)))) {
117856a34939Shaad log_error("lvmcache_info allocation failed");
117956a34939Shaad label_destroy(label);
118056a34939Shaad return NULL;
118156a34939Shaad }
118256a34939Shaad memset(info, 0, sizeof(*info));
118356a34939Shaad
118456a34939Shaad label->info = info;
118556a34939Shaad info->label = label;
118656a34939Shaad dm_list_init(&info->list);
118756a34939Shaad info->dev = dev;
118856a34939Shaad } else {
118956a34939Shaad if (existing->dev != dev) {
119056a34939Shaad /* Is the existing entry a duplicate pvid e.g. md ? */
1191*7c604eeaShaad if (dev_subsystem_part_major(existing->dev) &&
1192*7c604eeaShaad !dev_subsystem_part_major(dev)) {
119356a34939Shaad log_very_verbose("Ignoring duplicate PV %s on "
1194*7c604eeaShaad "%s - using %s %s",
119556a34939Shaad pvid, dev_name(dev),
1196*7c604eeaShaad dev_subsystem_name(existing->dev),
119756a34939Shaad dev_name(existing->dev));
119856a34939Shaad return NULL;
119956a34939Shaad } else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
120056a34939Shaad !dm_is_dm_major(MAJOR(dev->dev))) {
120156a34939Shaad log_very_verbose("Ignoring duplicate PV %s on "
120256a34939Shaad "%s - using dm %s",
120356a34939Shaad pvid, dev_name(dev),
120456a34939Shaad dev_name(existing->dev));
120556a34939Shaad return NULL;
1206*7c604eeaShaad } else if (!dev_subsystem_part_major(existing->dev) &&
1207*7c604eeaShaad dev_subsystem_part_major(dev))
120856a34939Shaad log_very_verbose("Duplicate PV %s on %s - "
1209*7c604eeaShaad "using %s %s", pvid,
121056a34939Shaad dev_name(existing->dev),
1211*7c604eeaShaad dev_subsystem_name(existing->dev),
121256a34939Shaad dev_name(dev));
121356a34939Shaad else if (!dm_is_dm_major(MAJOR(existing->dev->dev)) &&
121456a34939Shaad dm_is_dm_major(MAJOR(dev->dev)))
121556a34939Shaad log_very_verbose("Duplicate PV %s on %s - "
121656a34939Shaad "using dm %s", pvid,
121756a34939Shaad dev_name(existing->dev),
121856a34939Shaad dev_name(dev));
121956a34939Shaad /* FIXME If both dm, check dependencies */
122056a34939Shaad //else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
122156a34939Shaad //dm_is_dm_major(MAJOR(dev->dev)))
122256a34939Shaad //
1223bec4d750Shaad else if (!strcmp(pvid_s, existing->dev->pvid))
122456a34939Shaad log_error("Found duplicate PV %s: using %s not "
122556a34939Shaad "%s", pvid, dev_name(dev),
122656a34939Shaad dev_name(existing->dev));
122756a34939Shaad }
1228bec4d750Shaad if (strcmp(pvid_s, existing->dev->pvid))
1229bec4d750Shaad log_debug("Updating pvid cache to %s (%s) from %s (%s)",
1230bec4d750Shaad pvid_s, dev_name(dev),
1231bec4d750Shaad existing->dev->pvid, dev_name(existing->dev));
123256a34939Shaad /* Switch over to new preferred device */
123356a34939Shaad existing->dev = dev;
123456a34939Shaad info = existing;
123556a34939Shaad /* Has labeller changed? */
123656a34939Shaad if (info->label->labeller != labeller) {
123756a34939Shaad label_destroy(info->label);
123856a34939Shaad if (!(info->label = label_create(labeller)))
123956a34939Shaad /* FIXME leaves info without label! */
124056a34939Shaad return_NULL;
124156a34939Shaad info->label->info = info;
124256a34939Shaad }
124356a34939Shaad label = info->label;
124456a34939Shaad }
124556a34939Shaad
124656a34939Shaad info->fmt = (const struct format_type *) labeller->private;
124756a34939Shaad info->status |= CACHE_INVALID;
124856a34939Shaad
124956a34939Shaad if (!_lvmcache_update_pvid(info, pvid_s)) {
125056a34939Shaad if (!existing) {
125156a34939Shaad dm_free(info);
125256a34939Shaad label_destroy(label);
125356a34939Shaad }
125456a34939Shaad return NULL;
125556a34939Shaad }
125656a34939Shaad
125756a34939Shaad if (!lvmcache_update_vgname_and_id(info, vgname, vgid, vgstatus, NULL)) {
125856a34939Shaad if (!existing) {
125956a34939Shaad dm_hash_remove(_pvid_hash, pvid_s);
126056a34939Shaad strcpy(info->dev->pvid, "");
126156a34939Shaad dm_free(info);
126256a34939Shaad label_destroy(label);
126356a34939Shaad }
126456a34939Shaad return NULL;
126556a34939Shaad }
126656a34939Shaad
126756a34939Shaad return info;
126856a34939Shaad }
126956a34939Shaad
_lvmcache_destroy_entry(struct lvmcache_info * info)127056a34939Shaad static void _lvmcache_destroy_entry(struct lvmcache_info *info)
127156a34939Shaad {
127256a34939Shaad _vginfo_detach_info(info);
127356a34939Shaad strcpy(info->dev->pvid, "");
127456a34939Shaad label_destroy(info->label);
127556a34939Shaad dm_free(info);
127656a34939Shaad }
127756a34939Shaad
_lvmcache_destroy_vgnamelist(struct lvmcache_vginfo * vginfo)127856a34939Shaad static void _lvmcache_destroy_vgnamelist(struct lvmcache_vginfo *vginfo)
127956a34939Shaad {
128056a34939Shaad struct lvmcache_vginfo *next;
128156a34939Shaad
128256a34939Shaad do {
128356a34939Shaad next = vginfo->next;
128456a34939Shaad if (!_free_vginfo(vginfo))
128556a34939Shaad stack;
128656a34939Shaad } while ((vginfo = next));
128756a34939Shaad }
128856a34939Shaad
_lvmcache_destroy_lockname(struct dm_hash_node * n)128956a34939Shaad static void _lvmcache_destroy_lockname(struct dm_hash_node *n)
129056a34939Shaad {
129156a34939Shaad char *vgname;
129256a34939Shaad
129356a34939Shaad if (!dm_hash_get_data(_lock_hash, n))
129456a34939Shaad return;
129556a34939Shaad
129656a34939Shaad vgname = dm_hash_get_key(_lock_hash, n);
129756a34939Shaad
129856a34939Shaad if (!strcmp(vgname, VG_GLOBAL))
129956a34939Shaad _vg_global_lock_held = 1;
130056a34939Shaad else
130156a34939Shaad log_error("Internal error: Volume Group %s was not unlocked",
130256a34939Shaad dm_hash_get_key(_lock_hash, n));
130356a34939Shaad }
130456a34939Shaad
lvmcache_destroy(struct cmd_context * cmd,int retain_orphans)130556a34939Shaad void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans)
130656a34939Shaad {
130756a34939Shaad struct dm_hash_node *n;
130856a34939Shaad log_verbose("Wiping internal VG cache");
130956a34939Shaad
131056a34939Shaad _has_scanned = 0;
131156a34939Shaad
131256a34939Shaad if (_vgid_hash) {
131356a34939Shaad dm_hash_destroy(_vgid_hash);
131456a34939Shaad _vgid_hash = NULL;
131556a34939Shaad }
131656a34939Shaad
131756a34939Shaad if (_pvid_hash) {
131856a34939Shaad dm_hash_iter(_pvid_hash, (dm_hash_iterate_fn) _lvmcache_destroy_entry);
131956a34939Shaad dm_hash_destroy(_pvid_hash);
132056a34939Shaad _pvid_hash = NULL;
132156a34939Shaad }
132256a34939Shaad
132356a34939Shaad if (_vgname_hash) {
132456a34939Shaad dm_hash_iter(_vgname_hash,
132556a34939Shaad (dm_hash_iterate_fn) _lvmcache_destroy_vgnamelist);
132656a34939Shaad dm_hash_destroy(_vgname_hash);
132756a34939Shaad _vgname_hash = NULL;
132856a34939Shaad }
132956a34939Shaad
133056a34939Shaad if (_lock_hash) {
133156a34939Shaad dm_hash_iterate(n, _lock_hash)
133256a34939Shaad _lvmcache_destroy_lockname(n);
133356a34939Shaad dm_hash_destroy(_lock_hash);
133456a34939Shaad _lock_hash = NULL;
133556a34939Shaad }
133656a34939Shaad
133756a34939Shaad if (!dm_list_empty(&_vginfos))
133856a34939Shaad log_error("Internal error: _vginfos list should be empty");
133956a34939Shaad dm_list_init(&_vginfos);
134056a34939Shaad
134156a34939Shaad if (retain_orphans)
134256a34939Shaad init_lvmcache_orphans(cmd);
134356a34939Shaad }
1344