Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 : : * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
4 : : *
5 : : * This file is part of LVM2.
6 : : *
7 : : * This copyrighted material is made available to anyone wishing to use,
8 : : * modify, copy, or redistribute it subject to the terms and conditions
9 : : * of the GNU Lesser General Public License v.2.1.
10 : : *
11 : : * You should have received a copy of the GNU Lesser General Public License
12 : : * along with this program; if not, write to the Free Software Foundation,
13 : : * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 : : */
15 : :
16 : : #include "lib.h"
17 : : #include "lvmcache.h"
18 : : #include "toolcontext.h"
19 : : #include "dev-cache.h"
20 : : #include "locking.h"
21 : : #include "metadata.h"
22 : : #include "filter.h"
23 : : #include "filter-persistent.h"
24 : : #include "memlock.h"
25 : : #include "str_list.h"
26 : : #include "format-text.h"
27 : : #include "format_pool.h"
28 : : #include "format1.h"
29 : :
30 : : static struct dm_hash_table *_pvid_hash = NULL;
31 : : static struct dm_hash_table *_vgid_hash = NULL;
32 : : static struct dm_hash_table *_vgname_hash = NULL;
33 : : static struct dm_hash_table *_lock_hash = NULL;
34 : : static struct dm_list _vginfos;
35 : : static int _scanning_in_progress = 0;
36 : : static int _has_scanned = 0;
37 : : static int _vgs_locked = 0;
38 : : static int _vg_global_lock_held = 0; /* Global lock held when cache wiped? */
39 : :
40 : 3 : int lvmcache_init(void)
41 : : {
42 : : /*
43 : : * FIXME add a proper lvmcache_locking_reset() that
44 : : * resets the cache so no previous locks are locked
45 : : */
46 : 3 : _vgs_locked = 0;
47 : :
48 : 3 : dm_list_init(&_vginfos);
49 : :
50 [ - + ]: 3 : if (!(_vgname_hash = dm_hash_create(128)))
51 : 0 : return 0;
52 : :
53 [ - + ]: 3 : if (!(_vgid_hash = dm_hash_create(128)))
54 : 0 : return 0;
55 : :
56 [ - + ]: 3 : if (!(_pvid_hash = dm_hash_create(128)))
57 : 0 : return 0;
58 : :
59 [ - + ]: 3 : if (!(_lock_hash = dm_hash_create(128)))
60 : 0 : return 0;
61 : :
62 : : /*
63 : : * Reinitialising the cache clears the internal record of
64 : : * which locks are held. The global lock can be held during
65 : : * this operation so its state must be restored afterwards.
66 : : */
67 [ - + ]: 3 : if (_vg_global_lock_held) {
68 : 0 : lvmcache_lock_vgname(VG_GLOBAL, 0);
69 : 0 : _vg_global_lock_held = 0;
70 : : }
71 : :
72 : 3 : return 1;
73 : : }
74 : :
75 : : /* Volume Group metadata cache functions */
76 : 9 : static void _free_cached_vgmetadata(struct lvmcache_vginfo *vginfo)
77 : : {
78 [ + - ][ + - ]: 9 : if (!vginfo || !vginfo->vgmetadata)
79 : 9 : return;
80 : :
81 : 0 : dm_free(vginfo->vgmetadata);
82 : :
83 : 0 : vginfo->vgmetadata = NULL;
84 : :
85 : 9 : log_debug("Metadata cache: VG %s wiped.", vginfo->vgname);
86 : : }
87 : :
88 : : /*
89 : : * Cache VG metadata against the vginfo with matching vgid.
90 : : */
91 : 0 : static void _store_metadata(struct volume_group *vg, unsigned precommitted)
92 : : {
93 : : char uuid[64] __attribute((aligned(8)));
94 : : struct lvmcache_vginfo *vginfo;
95 : : int size;
96 : :
97 [ # # ]: 0 : if (!(vginfo = vginfo_from_vgid((const char *)&vg->id))) {
98 : 0 : stack;
99 : 0 : return;
100 : : }
101 : :
102 [ # # ]: 0 : if (vginfo->vgmetadata)
103 : 0 : _free_cached_vgmetadata(vginfo);
104 : :
105 [ # # ]: 0 : if (!(size = export_vg_to_buffer(vg, &vginfo->vgmetadata))) {
106 : 0 : stack;
107 : 0 : return;
108 : : }
109 : :
110 : 0 : vginfo->precommitted = precommitted;
111 : :
112 [ # # ]: 0 : if (!id_write_format((const struct id *)vginfo->vgid, uuid, sizeof(uuid))) {
113 : 0 : stack;
114 : 0 : return;
115 : : }
116 : :
117 [ # # ]: 0 : log_debug("Metadata cache: VG %s (%s) stored (%d bytes%s).",
118 : : vginfo->vgname, uuid, size,
119 : : precommitted ? ", precommitted" : "");
120 : : }
121 : :
122 : 0 : static void _update_cache_info_lock_state(struct lvmcache_info *info,
123 : : int locked,
124 : : int *cached_vgmetadata_valid)
125 : : {
126 : 0 : int was_locked = (info->status & CACHE_LOCKED) ? 1 : 0;
127 : :
128 : : /*
129 : : * Cache becomes invalid whenever lock state changes unless
130 : : * exclusive VG_GLOBAL is held (i.e. while scanning).
131 : : */
132 [ # # ][ # # ]: 0 : if (!vgname_is_locked(VG_GLOBAL) && (was_locked != locked)) {
133 : 0 : info->status |= CACHE_INVALID;
134 : 0 : *cached_vgmetadata_valid = 0;
135 : : }
136 : :
137 [ # # ]: 0 : if (locked)
138 : 0 : info->status |= CACHE_LOCKED;
139 : : else
140 : 0 : info->status &= ~CACHE_LOCKED;
141 : 0 : }
142 : :
143 : 9 : static void _update_cache_vginfo_lock_state(struct lvmcache_vginfo *vginfo,
144 : : int locked)
145 : : {
146 : : struct lvmcache_info *info;
147 : 9 : int cached_vgmetadata_valid = 1;
148 : :
149 [ - + ]: 9 : dm_list_iterate_items(info, &vginfo->infos)
150 : 0 : _update_cache_info_lock_state(info, locked,
151 : : &cached_vgmetadata_valid);
152 : :
153 [ - + ]: 9 : if (!cached_vgmetadata_valid)
154 : 0 : _free_cached_vgmetadata(vginfo);
155 : 9 : }
156 : :
157 : 2 : static void _update_cache_lock_state(const char *vgname, int locked)
158 : : {
159 : : struct lvmcache_vginfo *vginfo;
160 : :
161 [ + - ]: 2 : if (!(vginfo = vginfo_from_vgname(vgname, NULL)))
162 : 2 : return;
163 : :
164 : 2 : _update_cache_vginfo_lock_state(vginfo, locked);
165 : : }
166 : :
167 : 0 : static void _drop_metadata(const char *vgname, int drop_precommitted)
168 : : {
169 : : struct lvmcache_vginfo *vginfo;
170 : : struct lvmcache_info *info;
171 : :
172 [ # # ]: 0 : if (!(vginfo = vginfo_from_vgname(vgname, NULL)))
173 : 0 : return;
174 : :
175 : : /*
176 : : * Invalidate cached PV labels.
177 : : * If cached precommitted metadata exists that means we
178 : : * already invalidated the PV labels (before caching it)
179 : : * and we must not do it again.
180 : : */
181 [ # # ][ # # ]: 0 : if (!drop_precommitted && vginfo->precommitted && !vginfo->vgmetadata)
[ # # ]
182 : 0 : log_error(INTERNAL_ERROR "metadata commit (or revert) missing before "
183 : : "dropping metadata from cache.");
184 : :
185 [ # # ][ # # ]: 0 : if (drop_precommitted || !vginfo->precommitted)
186 [ # # ]: 0 : dm_list_iterate_items(info, &vginfo->infos)
187 : 0 : info->status |= CACHE_INVALID;
188 : :
189 : 0 : _free_cached_vgmetadata(vginfo);
190 : : }
191 : :
192 : : /*
193 : : * Remote node uses this to upgrade precommited metadata to commited state
194 : : * when receives vg_commit notification.
195 : : * (Note that devices can be suspended here, if so, precommited metadata are already read.)
196 : : */
197 : 0 : void lvmcache_commit_metadata(const char *vgname)
198 : : {
199 : : struct lvmcache_vginfo *vginfo;
200 : :
201 [ # # ]: 0 : if (!(vginfo = vginfo_from_vgname(vgname, NULL)))
202 : 0 : return;
203 : :
204 [ # # ]: 0 : if (vginfo->precommitted) {
205 : 0 : log_debug("Precommitted metadata cache: VG %s upgraded to committed.",
206 : : vginfo->vgname);
207 : 0 : vginfo->precommitted = 0;
208 : : }
209 : : }
210 : :
211 : 0 : void lvmcache_drop_metadata(const char *vgname, int drop_precommitted)
212 : : {
213 : : /* For VG_ORPHANS, we need to invalidate all labels on orphan PVs. */
214 [ # # ]: 0 : if (!strcmp(vgname, VG_ORPHANS)) {
215 : 0 : _drop_metadata(FMT_TEXT_ORPHAN_VG_NAME, 0);
216 : 0 : _drop_metadata(FMT_LVM1_ORPHAN_VG_NAME, 0);
217 : 0 : _drop_metadata(FMT_POOL_ORPHAN_VG_NAME, 0);
218 : :
219 : : /* Indicate that PVs could now be missing from the cache */
220 : 0 : init_full_scan_done(0);
221 [ # # ]: 0 : } else if (!vgname_is_locked(VG_GLOBAL))
222 : 0 : _drop_metadata(vgname, drop_precommitted);
223 : 0 : }
224 : :
225 : : /*
226 : : * Ensure vgname2 comes after vgname1 alphabetically.
227 : : * Special VG names beginning with '#' don't count.
228 : : */
229 : 0 : static int _vgname_order_correct(const char *vgname1, const char *vgname2)
230 : : {
231 [ # # ][ # # ]: 0 : if ((*vgname1 == '#') || (*vgname2 == '#'))
232 : 0 : return 1;
233 : :
234 [ # # ]: 0 : if (strcmp(vgname1, vgname2) < 0)
235 : 0 : return 1;
236 : :
237 : 0 : return 0;
238 : : }
239 : :
240 : : /*
241 : : * Ensure VG locks are acquired in alphabetical order.
242 : : */
243 : 0 : int lvmcache_verify_lock_order(const char *vgname)
244 : : {
245 : : struct dm_hash_node *n;
246 : : const char *vgname2;
247 : :
248 [ # # ]: 0 : if (!_lock_hash)
249 : 0 : return_0;
250 : :
251 [ # # ]: 0 : dm_hash_iterate(n, _lock_hash) {
252 [ # # ]: 0 : if (!dm_hash_get_data(_lock_hash, n))
253 : 0 : return_0;
254 : :
255 : 0 : vgname2 = dm_hash_get_key(_lock_hash, n);
256 : :
257 [ # # ]: 0 : if (!_vgname_order_correct(vgname2, vgname)) {
258 : 0 : log_errno(EDEADLK, INTERNAL_ERROR "VG lock %s must "
259 : : "be requested before %s, not after.",
260 : : vgname, vgname2);
261 : 0 : return_0;
262 : : }
263 : : }
264 : :
265 : 0 : return 1;
266 : : }
267 : :
268 : 1 : void lvmcache_lock_vgname(const char *vgname, int read_only __attribute((unused)))
269 : : {
270 [ - + ][ # # ]: 1 : if (!_lock_hash && !lvmcache_init()) {
271 : 0 : log_error("Internal cache initialisation failed");
272 : 0 : return;
273 : : }
274 : :
275 [ - + ]: 1 : if (dm_hash_lookup(_lock_hash, vgname))
276 : 0 : log_error(INTERNAL_ERROR "Nested locking attempted on VG %s.",
277 : : vgname);
278 : :
279 [ - + ]: 1 : if (!dm_hash_insert(_lock_hash, vgname, (void *) 1))
280 : 0 : log_error("Cache locking failure for %s", vgname);
281 : :
282 : 1 : _update_cache_lock_state(vgname, 1);
283 : :
284 [ - + ]: 1 : if (strcmp(vgname, VG_GLOBAL))
285 : 1 : _vgs_locked++;
286 : : }
287 : :
288 : 9 : int vgname_is_locked(const char *vgname)
289 : : {
290 [ - + ]: 9 : if (!_lock_hash)
291 : 0 : return 0;
292 : :
293 : 9 : return dm_hash_lookup(_lock_hash, vgname) ? 1 : 0;
294 : : }
295 : :
296 : 1 : void lvmcache_unlock_vgname(const char *vgname)
297 : : {
298 [ - + ]: 1 : if (!dm_hash_lookup(_lock_hash, vgname))
299 : 0 : log_error(INTERNAL_ERROR "Attempt to unlock unlocked VG %s.",
300 : : vgname);
301 : :
302 : 1 : _update_cache_lock_state(vgname, 0);
303 : :
304 : 1 : dm_hash_remove(_lock_hash, vgname);
305 : :
306 : : /* FIXME Do this per-VG */
307 [ - + # # ]: 1 : if (strcmp(vgname, VG_GLOBAL) && !--_vgs_locked)
308 : 0 : dev_close_all();
309 : 1 : }
310 : :
311 : 0 : int vgs_locked(void)
312 : : {
313 : 0 : return _vgs_locked;
314 : : }
315 : :
316 : 0 : static void _vginfo_attach_info(struct lvmcache_vginfo *vginfo,
317 : : struct lvmcache_info *info)
318 : : {
319 [ # # ]: 0 : if (!vginfo)
320 : 0 : return;
321 : :
322 : 0 : info->vginfo = vginfo;
323 : 0 : dm_list_add(&vginfo->infos, &info->list);
324 : : }
325 : :
326 : 0 : static void _vginfo_detach_info(struct lvmcache_info *info)
327 : : {
328 [ # # ]: 0 : if (!dm_list_empty(&info->list)) {
329 : 0 : dm_list_del(&info->list);
330 : 0 : dm_list_init(&info->list);
331 : : }
332 : :
333 : 0 : info->vginfo = NULL;
334 : 0 : }
335 : :
336 : : /* If vgid supplied, require a match. */
337 : 33 : struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname, const char *vgid)
338 : : {
339 : : struct lvmcache_vginfo *vginfo;
340 : :
341 [ - + ]: 33 : if (!vgname)
342 : 0 : return vginfo_from_vgid(vgid);
343 : :
344 [ - + ]: 33 : if (!_vgname_hash)
345 : 0 : return NULL;
346 : :
347 [ + + ]: 33 : if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname)))
348 : 20 : return NULL;
349 : :
350 [ - + ]: 13 : if (vgid)
351 : : do
352 [ # # ]: 0 : if (!strncmp(vgid, vginfo->vgid, ID_LEN))
353 : 0 : return vginfo;
354 [ # # ]: 0 : while ((vginfo = vginfo->next));
355 : :
356 : 33 : return vginfo;
357 : : }
358 : :
359 : 0 : const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
360 : : {
361 : : struct lvmcache_vginfo *vginfo;
362 : : struct lvmcache_info *info;
363 : : struct label *label;
364 : : struct dm_list *devh, *tmp;
365 : : struct dm_list devs;
366 : : struct device_list *devl;
367 : : char vgid_found[ID_LEN + 1] __attribute((aligned(8)));
368 : :
369 [ # # ]: 0 : if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
370 : 0 : return NULL;
371 : :
372 : : /* This function is normally called before reading metadata so
373 : : * we check cached labels here. Unfortunately vginfo is volatile. */
374 : 0 : dm_list_init(&devs);
375 [ # # ]: 0 : dm_list_iterate_items(info, &vginfo->infos) {
376 [ # # ]: 0 : if (!(devl = dm_malloc(sizeof(*devl)))) {
377 : 0 : log_error("device_list element allocation failed");
378 : 0 : return NULL;
379 : : }
380 : 0 : devl->dev = info->dev;
381 : 0 : dm_list_add(&devs, &devl->list);
382 : : }
383 : :
384 : 0 : memcpy(vgid_found, vginfo->vgid, sizeof(vgid_found));
385 : :
386 [ # # ]: 0 : dm_list_iterate_safe(devh, tmp, &devs) {
387 : 0 : devl = dm_list_item(devh, struct device_list);
388 : 0 : label_read(devl->dev, &label, UINT64_C(0));
389 : 0 : dm_list_del(&devl->list);
390 : 0 : dm_free(devl);
391 : : }
392 : :
393 : : /* If vginfo changed, caller needs to rescan */
394 [ # # ][ # # ]: 0 : if (!(vginfo = vginfo_from_vgname(vgname, vgid_found)) ||
395 : 0 : strncmp(vginfo->vgid, vgid_found, ID_LEN))
396 : 0 : return NULL;
397 : :
398 : 0 : return vginfo->fmt;
399 : : }
400 : :
401 : 3 : struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid)
402 : : {
403 : : struct lvmcache_vginfo *vginfo;
404 : : char id[ID_LEN + 1] __attribute((aligned(8)));
405 : :
406 [ + - ][ - + ]: 3 : if (!_vgid_hash || !vgid)
407 : 0 : return NULL;
408 : :
409 : : /* vgid not necessarily NULL-terminated */
410 : 3 : strncpy(&id[0], vgid, ID_LEN);
411 : 3 : id[ID_LEN] = '\0';
412 : :
413 [ - + ]: 3 : if (!(vginfo = dm_hash_lookup(_vgid_hash, id)))
414 : 0 : return NULL;
415 : :
416 : 3 : return vginfo;
417 : : }
418 : :
419 : 3 : const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid)
420 : : {
421 : : struct lvmcache_vginfo *vginfo;
422 : 3 : const char *vgname = NULL;
423 : :
424 [ + - ]: 3 : if ((vginfo = vginfo_from_vgid(vgid)))
425 : 3 : vgname = vginfo->vgname;
426 : :
427 [ - + ][ # # ]: 3 : if (mem && vgname)
428 : 0 : return dm_pool_strdup(mem, vgname);
429 : :
430 : 3 : return vgname;
431 : : }
432 : :
433 : 0 : static int _info_is_valid(struct lvmcache_info *info)
434 : : {
435 [ # # ]: 0 : if (info->status & CACHE_INVALID)
436 : 0 : return 0;
437 : :
438 : : /*
439 : : * The caller must hold the VG lock to manipulate metadata.
440 : : * In a cluster, remote nodes sometimes read metadata in the
441 : : * knowledge that the controlling node is holding the lock.
442 : : * So if the VG appears to be unlocked here, it should be safe
443 : : * to use the cached value.
444 : : */
445 [ # # ][ # # ]: 0 : if (info->vginfo && !vgname_is_locked(info->vginfo->vgname))
446 : 0 : return 1;
447 : :
448 [ # # ]: 0 : if (!(info->status & CACHE_LOCKED))
449 : 0 : return 0;
450 : :
451 : 0 : return 1;
452 : : }
453 : :
454 : 0 : static int _vginfo_is_valid(struct lvmcache_vginfo *vginfo)
455 : : {
456 : : struct lvmcache_info *info;
457 : :
458 : : /* Invalid if any info is invalid */
459 [ # # ]: 0 : dm_list_iterate_items(info, &vginfo->infos)
460 [ # # ]: 0 : if (!_info_is_valid(info))
461 : 0 : return 0;
462 : :
463 : 0 : return 1;
464 : : }
465 : :
466 : : /* vginfo is invalid if it does not contain at least one valid info */
467 : 0 : static int _vginfo_is_invalid(struct lvmcache_vginfo *vginfo)
468 : : {
469 : : struct lvmcache_info *info;
470 : :
471 [ # # ]: 0 : dm_list_iterate_items(info, &vginfo->infos)
472 [ # # ]: 0 : if (_info_is_valid(info))
473 : 0 : return 0;
474 : :
475 : 0 : return 1;
476 : : }
477 : :
478 : : /*
479 : : * If valid_only is set, data will only be returned if the cached data is
480 : : * known still to be valid.
481 : : */
482 : 4 : struct lvmcache_info *info_from_pvid(const char *pvid, int valid_only)
483 : : {
484 : : struct lvmcache_info *info;
485 : : char id[ID_LEN + 1] __attribute((aligned(8)));
486 : :
487 [ - + ][ # # ]: 4 : if (!_pvid_hash || !pvid)
488 : 4 : return NULL;
489 : :
490 : 0 : strncpy(&id[0], pvid, ID_LEN);
491 : 0 : id[ID_LEN] = '\0';
492 : :
493 [ # # ]: 0 : if (!(info = dm_hash_lookup(_pvid_hash, id)))
494 : 0 : return NULL;
495 : :
496 [ # # ][ # # ]: 0 : if (valid_only && !_info_is_valid(info))
497 : 0 : return NULL;
498 : :
499 : 4 : return info;
500 : : }
501 : :
502 : 0 : static void _rescan_entry(struct lvmcache_info *info)
503 : : {
504 : : struct label *label;
505 : :
506 [ # # ]: 0 : if (info->status & CACHE_INVALID)
507 : 0 : label_read(info->dev, &label, UINT64_C(0));
508 : 0 : }
509 : :
510 : 5 : static int _scan_invalid(void)
511 : : {
512 : 5 : dm_hash_iter(_pvid_hash, (dm_hash_iterate_fn) _rescan_entry);
513 : :
514 : 5 : return 1;
515 : : }
516 : :
517 : 6 : int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
518 : : {
519 : : struct label *label;
520 : : struct dev_iter *iter;
521 : : struct device *dev;
522 : : struct format_type *fmt;
523 : :
524 : 6 : int r = 0;
525 : :
526 : : /* Avoid recursion when a PVID can't be found! */
527 [ - + ]: 6 : if (_scanning_in_progress)
528 : 0 : return 0;
529 : :
530 : 6 : _scanning_in_progress = 1;
531 : :
532 [ - + ][ # # ]: 6 : if (!_vgname_hash && !lvmcache_init()) {
533 : 0 : log_error("Internal cache initialisation failed");
534 : 0 : goto out;
535 : : }
536 : :
537 [ + + ][ + - ]: 6 : if (_has_scanned && !full_scan) {
538 : 5 : r = _scan_invalid();
539 : 5 : goto out;
540 : : }
541 : :
542 [ - + ][ # # ]: 1 : if (full_scan == 2 && !refresh_filters(cmd)) {
543 : 0 : log_error("refresh filters failed");
544 : 0 : goto out;
545 : : }
546 : :
547 [ - + ]: 1 : if (!(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1 : 0))) {
548 : 0 : log_error("dev_iter creation failed");
549 : 0 : goto out;
550 : : }
551 : :
552 [ - + ]: 1 : while ((dev = dev_iter_get(iter)))
553 : 0 : label_read(dev, &label, UINT64_C(0));
554 : :
555 : 1 : dev_iter_destroy(iter);
556 : :
557 : 1 : _has_scanned = 1;
558 : :
559 : : /* Perform any format-specific scanning e.g. text files */
560 [ + + ]: 4 : dm_list_iterate_items(fmt, &cmd->formats) {
561 [ + + ][ - + ]: 3 : if (fmt->ops->scan && !fmt->ops->scan(fmt))
562 : 0 : goto out;
563 : : }
564 : :
565 : : /*
566 : : * If we are a long-lived process, write out the updated persistent
567 : : * device cache for the benefit of short-lived processes.
568 : : */
569 [ - + ][ # # ]: 1 : if (full_scan == 2 && cmd->is_long_lived && cmd->dump_filter)
[ # # ]
570 : 0 : persistent_filter_dump(cmd->filter);
571 : :
572 : 1 : r = 1;
573 : :
574 : : out:
575 : 6 : _scanning_in_progress = 0;
576 : :
577 : 6 : return r;
578 : : }
579 : :
580 : 0 : struct volume_group *lvmcache_get_vg(const char *vgid, unsigned precommitted)
581 : : {
582 : : struct lvmcache_vginfo *vginfo;
583 : : struct volume_group *vg;
584 : : struct format_instance *fid;
585 : :
586 [ # # ][ # # ]: 0 : if (!vgid || !(vginfo = vginfo_from_vgid(vgid)) || !vginfo->vgmetadata)
[ # # ]
587 : 0 : return NULL;
588 : :
589 [ # # ]: 0 : if (!_vginfo_is_valid(vginfo))
590 : 0 : return NULL;
591 : :
592 : : /*
593 : : * Don't return cached data if either:
594 : : * (i) precommitted metadata is requested but we don't have it cached
595 : : * - caller should read it off disk;
596 : : * (ii) live metadata is requested but we have precommitted metadata cached
597 : : * and no devices are suspended so caller may read it off disk.
598 : : *
599 : : * If live metadata is requested but we have precommitted metadata cached
600 : : * and devices are suspended, we assume this precommitted metadata has
601 : : * already been preloaded and committed so it's OK to return it as live.
602 : : * Note that we do not clear the PRECOMMITTED flag.
603 : : */
604 [ # # ][ # # ]: 0 : if ((precommitted && !vginfo->precommitted) ||
[ # # ]
[ # # # # ]
605 : 0 : (!precommitted && vginfo->precommitted && !memlock()))
606 : 0 : return NULL;
607 : :
608 [ # # ]: 0 : if (!(fid = vginfo->fmt->ops->create_instance(vginfo->fmt,
609 : 0 : vginfo->vgname,
610 : : vgid, NULL)))
611 : 0 : return_NULL;
612 : :
613 [ # # ]: 0 : if (!(vg = import_vg_from_buffer(vginfo->vgmetadata, fid))) {
614 : 0 : _free_cached_vgmetadata(vginfo);
615 : 0 : vg_release(vg);
616 : 0 : return_NULL;
617 : : }
618 : :
619 [ # # ]: 0 : log_debug("Using cached %smetadata for VG %s.",
620 : : vginfo->precommitted ? "pre-committed" : "", vginfo->vgname);
621 : :
622 : 0 : return vg;
623 : : }
624 : :
625 : 1 : struct dm_list *lvmcache_get_vgids(struct cmd_context *cmd,
626 : : int include_internal)
627 : : {
628 : : struct dm_list *vgids;
629 : : struct lvmcache_vginfo *vginfo;
630 : :
631 : 1 : lvmcache_label_scan(cmd, 0);
632 : :
633 [ - + ]: 1 : if (!(vgids = str_list_create(cmd->mem))) {
634 : 0 : log_error("vgids list allocation failed");
635 : 0 : return NULL;
636 : : }
637 : :
638 [ + + ]: 4 : dm_list_iterate_items(vginfo, &_vginfos) {
639 [ - + ][ # # ]: 3 : if (!include_internal && is_orphan_vg(vginfo->vgname))
640 : 0 : continue;
641 : :
642 [ - + ]: 3 : if (!str_list_add(cmd->mem, vgids,
643 : 3 : dm_pool_strdup(cmd->mem, vginfo->vgid))) {
644 : 0 : log_error("strlist allocation failed");
645 : 0 : return NULL;
646 : : }
647 : : }
648 : :
649 : 1 : return vgids;
650 : : }
651 : :
652 : 0 : struct dm_list *lvmcache_get_vgnames(struct cmd_context *cmd,
653 : : int include_internal)
654 : : {
655 : : struct dm_list *vgnames;
656 : : struct lvmcache_vginfo *vginfo;
657 : :
658 : 0 : lvmcache_label_scan(cmd, 0);
659 : :
660 [ # # ]: 0 : if (!(vgnames = str_list_create(cmd->mem))) {
661 : 0 : log_errno(ENOMEM, "vgnames list allocation failed");
662 : 0 : return NULL;
663 : : }
664 : :
665 [ # # ]: 0 : dm_list_iterate_items(vginfo, &_vginfos) {
666 [ # # ][ # # ]: 0 : if (!include_internal && is_orphan_vg(vginfo->vgname))
667 : 0 : continue;
668 : :
669 [ # # ]: 0 : if (!str_list_add(cmd->mem, vgnames,
670 : 0 : dm_pool_strdup(cmd->mem, vginfo->vgname))) {
671 : 0 : log_errno(ENOMEM, "strlist allocation failed");
672 : 0 : return NULL;
673 : : }
674 : : }
675 : :
676 : 0 : return vgnames;
677 : : }
678 : :
679 : 0 : struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
680 : : const char *vgid)
681 : : {
682 : : struct dm_list *pvids;
683 : : struct lvmcache_vginfo *vginfo;
684 : : struct lvmcache_info *info;
685 : :
686 [ # # ]: 0 : if (!(pvids = str_list_create(cmd->mem))) {
687 : 0 : log_error("pvids list allocation failed");
688 : 0 : return NULL;
689 : : }
690 : :
691 [ # # ]: 0 : if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
692 : 0 : return pvids;
693 : :
694 [ # # ]: 0 : dm_list_iterate_items(info, &vginfo->infos) {
695 [ # # ]: 0 : if (!str_list_add(cmd->mem, pvids,
696 : 0 : dm_pool_strdup(cmd->mem, info->dev->pvid))) {
697 : 0 : log_error("strlist allocation failed");
698 : 0 : return NULL;
699 : : }
700 : : }
701 : :
702 : 0 : return pvids;
703 : : }
704 : :
705 : 0 : struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid,
706 : : unsigned *scan_done_once)
707 : : {
708 : : struct label *label;
709 : : struct lvmcache_info *info;
710 : :
711 : : /* Already cached ? */
712 [ # # ]: 0 : if ((info = info_from_pvid((char *) pvid, 0))) {
713 [ # # ]: 0 : if (label_read(info->dev, &label, UINT64_C(0))) {
714 : 0 : info = (struct lvmcache_info *) label->info;
715 [ # # ]: 0 : if (id_equal(pvid, (struct id *) &info->dev->pvid))
716 : 0 : return info->dev;
717 : : }
718 : : }
719 : :
720 : 0 : lvmcache_label_scan(cmd, 0);
721 : :
722 : : /* Try again */
723 [ # # ]: 0 : if ((info = info_from_pvid((char *) pvid, 0))) {
724 [ # # ]: 0 : if (label_read(info->dev, &label, UINT64_C(0))) {
725 : 0 : info = (struct lvmcache_info *) label->info;
726 [ # # ]: 0 : if (id_equal(pvid, (struct id *) &info->dev->pvid))
727 : 0 : return info->dev;
728 : : }
729 : : }
730 : :
731 [ # # ][ # # ]: 0 : if (memlock() || (scan_done_once && *scan_done_once))
[ # # ]
732 : 0 : return NULL;
733 : :
734 : 0 : lvmcache_label_scan(cmd, 2);
735 [ # # ]: 0 : if (scan_done_once)
736 : 0 : *scan_done_once = 1;
737 : :
738 : : /* Try again */
739 [ # # ]: 0 : if ((info = info_from_pvid((char *) pvid, 0))) {
740 [ # # ]: 0 : if (label_read(info->dev, &label, UINT64_C(0))) {
741 : 0 : info = (struct lvmcache_info *) label->info;
742 [ # # ]: 0 : if (id_equal(pvid, (struct id *) &info->dev->pvid))
743 : 0 : return info->dev;
744 : : }
745 : : }
746 : :
747 : 0 : return NULL;
748 : : }
749 : :
750 : 9 : static int _free_vginfo(struct lvmcache_vginfo *vginfo)
751 : : {
752 : : struct lvmcache_vginfo *primary_vginfo, *vginfo2;
753 : 9 : int r = 1;
754 : :
755 : 9 : _free_cached_vgmetadata(vginfo);
756 : :
757 : 9 : vginfo2 = primary_vginfo = vginfo_from_vgname(vginfo->vgname, NULL);
758 : :
759 [ + - ]: 9 : if (vginfo == primary_vginfo) {
760 : 9 : dm_hash_remove(_vgname_hash, vginfo->vgname);
761 [ - + # # ]: 9 : if (vginfo->next && !dm_hash_insert(_vgname_hash, vginfo->vgname,
762 : 0 : vginfo->next)) {
763 : 0 : log_error("_vgname_hash re-insertion for %s failed",
764 : : vginfo->vgname);
765 : 9 : r = 0;
766 : : }
767 : : } else do
768 [ # # ]: 0 : if (vginfo2->next == vginfo) {
769 : 0 : vginfo2->next = vginfo->next;
770 : 0 : break;
771 : : }
772 [ # # ]: 0 : while ((vginfo2 = primary_vginfo->next));
773 : :
774 [ + - ]: 9 : if (vginfo->vgname)
775 : 9 : dm_free(vginfo->vgname);
776 : :
777 [ - + ]: 9 : if (vginfo->creation_host)
778 : 0 : dm_free(vginfo->creation_host);
779 : :
780 [ + - ]: 9 : if (*vginfo->vgid && _vgid_hash &&
[ - + # # ]
781 : 0 : vginfo_from_vgid(vginfo->vgid) == vginfo)
782 : 0 : dm_hash_remove(_vgid_hash, vginfo->vgid);
783 : :
784 : 9 : dm_list_del(&vginfo->list);
785 : :
786 : 9 : dm_free(vginfo);
787 : :
788 : 9 : return r;
789 : : }
790 : :
791 : : /*
792 : : * vginfo must be info->vginfo unless info is NULL
793 : : */
794 : 0 : static int _drop_vginfo(struct lvmcache_info *info, struct lvmcache_vginfo *vginfo)
795 : : {
796 [ # # ]: 0 : if (info)
797 : 0 : _vginfo_detach_info(info);
798 : :
799 : : /* vginfo still referenced? */
800 [ # # ]: 0 : if (!vginfo || is_orphan_vg(vginfo->vgname) ||
[ # # # # ]
801 : 0 : !dm_list_empty(&vginfo->infos))
802 : 0 : return 1;
803 : :
804 [ # # ]: 0 : if (!_free_vginfo(vginfo))
805 : 0 : return_0;
806 : :
807 : 0 : return 1;
808 : : }
809 : :
810 : : /* Unused
811 : : void lvmcache_del(struct lvmcache_info *info)
812 : : {
813 : : if (info->dev->pvid[0] && _pvid_hash)
814 : : dm_hash_remove(_pvid_hash, info->dev->pvid);
815 : :
816 : : _drop_vginfo(info, info->vginfo);
817 : :
818 : : info->label->labeller->ops->destroy_label(info->label->labeller,
819 : : info->label);
820 : : dm_free(info);
821 : :
822 : : return;
823 : : } */
824 : :
825 : 0 : static int _lvmcache_update_pvid(struct lvmcache_info *info, const char *pvid)
826 : : {
827 : : /*
828 : : * Nothing to do if already stored with same pvid.
829 : : */
830 [ # # ][ # # ]: 0 : if (((dm_hash_lookup(_pvid_hash, pvid)) == info) &&
831 : 0 : !strcmp(info->dev->pvid, pvid))
832 : 0 : return 1;
833 [ # # ]: 0 : if (*info->dev->pvid)
834 : 0 : dm_hash_remove(_pvid_hash, info->dev->pvid);
835 : 0 : strncpy(info->dev->pvid, pvid, sizeof(info->dev->pvid));
836 [ # # ]: 0 : if (!dm_hash_insert(_pvid_hash, pvid, info)) {
837 : 0 : log_error("_lvmcache_update: pvid insertion failed: %s", pvid);
838 : 0 : return 0;
839 : : }
840 : :
841 : 0 : return 1;
842 : : }
843 : :
844 : : /*
845 : : * vginfo must be info->vginfo unless info is NULL (orphans)
846 : : */
847 : 9 : static int _lvmcache_update_vgid(struct lvmcache_info *info,
848 : : struct lvmcache_vginfo *vginfo,
849 : : const char *vgid)
850 : : {
851 [ + - ][ + - ]: 9 : if (!vgid || !vginfo ||
[ - + ]
852 : 9 : !strncmp(vginfo->vgid, vgid, ID_LEN))
853 : 0 : return 1;
854 : :
855 [ + - ][ - + ]: 9 : if (vginfo && *vginfo->vgid)
856 : 0 : dm_hash_remove(_vgid_hash, vginfo->vgid);
857 [ - + ]: 9 : if (!vgid) {
858 [ # # ]: 0 : log_debug("lvmcache: %s: clearing VGID", info ? dev_name(info->dev) : vginfo->vgname);
859 : 0 : return 1;
860 : : }
861 : :
862 : 9 : strncpy(vginfo->vgid, vgid, ID_LEN);
863 : 9 : vginfo->vgid[ID_LEN] = '\0';
864 [ - + ]: 9 : if (!dm_hash_insert(_vgid_hash, vginfo->vgid, vginfo)) {
865 : 0 : log_error("_lvmcache_update: vgid hash insertion failed: %s",
866 : : vginfo->vgid);
867 : 0 : return 0;
868 : : }
869 : :
870 [ - + ]: 9 : if (!is_orphan_vg(vginfo->vgname))
871 : 0 : log_debug("lvmcache: %s: setting %s VGID to %s",
872 : : dev_name(info->dev), vginfo->vgname,
873 : : vginfo->vgid);
874 : :
875 : 9 : return 1;
876 : : }
877 : :
878 : 9 : static int _insert_vginfo(struct lvmcache_vginfo *new_vginfo, const char *vgid,
879 : : uint32_t vgstatus, const char *creation_host,
880 : : struct lvmcache_vginfo *primary_vginfo)
881 : : {
882 : 9 : struct lvmcache_vginfo *last_vginfo = primary_vginfo;
883 : : char uuid_primary[64] __attribute((aligned(8)));
884 : : char uuid_new[64] __attribute((aligned(8)));
885 : 9 : int use_new = 0;
886 : :
887 : : /* Pre-existing VG takes precedence. Unexported VG takes precedence. */
888 [ - + ]: 9 : if (primary_vginfo) {
889 [ # # ]: 0 : if (!id_write_format((const struct id *)vgid, uuid_new, sizeof(uuid_new)))
890 : 0 : return_0;
891 : :
892 [ # # ]: 0 : if (!id_write_format((const struct id *)&primary_vginfo->vgid, uuid_primary,
893 : : sizeof(uuid_primary)))
894 : 0 : return_0;
895 : :
896 : : /*
897 : : * If Primary not exported, new exported => keep
898 : : * Else Primary exported, new not exported => change
899 : : * Else Primary has hostname for this machine => keep
900 : : * Else Primary has no hostname, new has one => change
901 : : * Else New has hostname for this machine => change
902 : : * Else Keep primary.
903 : : */
904 [ # # ][ # # ]: 0 : if (!(primary_vginfo->status & EXPORTED_VG) &&
905 : 0 : (vgstatus & EXPORTED_VG))
906 : 0 : log_warn("WARNING: Duplicate VG name %s: "
907 : : "Existing %s takes precedence over "
908 : : "exported %s", new_vginfo->vgname,
909 : : uuid_primary, uuid_new);
910 [ # # ][ # # ]: 0 : else if ((primary_vginfo->status & EXPORTED_VG) &&
911 : 0 : !(vgstatus & EXPORTED_VG)) {
912 : 0 : log_warn("WARNING: Duplicate VG name %s: "
913 : : "%s takes precedence over exported %s",
914 : : new_vginfo->vgname, uuid_new,
915 : : uuid_primary);
916 : 0 : use_new = 1;
917 [ # # ][ # # ]: 0 : } else if (primary_vginfo->creation_host &&
918 : 0 : !strcmp(primary_vginfo->creation_host,
919 : 0 : primary_vginfo->fmt->cmd->hostname))
920 : 0 : log_warn("WARNING: Duplicate VG name %s: "
921 : : "Existing %s (created here) takes precedence "
922 : : "over %s", new_vginfo->vgname, uuid_primary,
923 : : uuid_new);
924 [ # # ][ # # ]: 0 : else if (!primary_vginfo->creation_host && creation_host) {
925 : 0 : log_warn("WARNING: Duplicate VG name %s: "
926 : : "%s (with creation_host) takes precedence over %s",
927 : : new_vginfo->vgname, uuid_new,
928 : : uuid_primary);
929 : 0 : use_new = 1;
930 [ # # ][ # # ]: 0 : } else if (creation_host &&
931 : 0 : !strcmp(creation_host,
932 : 0 : primary_vginfo->fmt->cmd->hostname)) {
933 : 0 : log_warn("WARNING: Duplicate VG name %s: "
934 : : "%s (created here) takes precedence over %s",
935 : : new_vginfo->vgname, uuid_new,
936 : : uuid_primary);
937 : 0 : use_new = 1;
938 : : }
939 : :
940 [ # # ]: 0 : if (!use_new) {
941 [ # # ]: 0 : while (last_vginfo->next)
942 : 0 : last_vginfo = last_vginfo->next;
943 : 0 : last_vginfo->next = new_vginfo;
944 : 0 : return 1;
945 : : }
946 : :
947 : 0 : dm_hash_remove(_vgname_hash, primary_vginfo->vgname);
948 : : }
949 : :
950 [ - + ]: 9 : if (!dm_hash_insert(_vgname_hash, new_vginfo->vgname, new_vginfo)) {
951 : 0 : log_error("cache_update: vg hash insertion failed: %s",
952 : : new_vginfo->vgname);
953 : 0 : return 0;
954 : : }
955 : :
956 [ - + ]: 9 : if (primary_vginfo)
957 : 0 : new_vginfo->next = primary_vginfo;
958 : :
959 : 9 : return 1;
960 : : }
961 : :
962 : 9 : static int _lvmcache_update_vgname(struct lvmcache_info *info,
963 : : const char *vgname, const char *vgid,
964 : : uint32_t vgstatus, const char *creation_host,
965 : : const struct format_type *fmt)
966 : : {
967 : : struct lvmcache_vginfo *vginfo, *primary_vginfo, *orphan_vginfo;
968 : : struct lvmcache_info *info2, *info3;
969 : : char mdabuf[32];
970 : : // struct lvmcache_vginfo *old_vginfo, *next;
971 : :
972 [ + - ][ - + ]: 9 : if (!vgname || (info && info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
[ # # ][ # # ]
973 : 0 : return 1;
974 : :
975 : : /* Remove existing vginfo entry */
976 [ - + ]: 9 : if (info)
977 : 0 : _drop_vginfo(info, info->vginfo);
978 : :
979 : : /* Get existing vginfo or create new one */
980 [ + - ]: 9 : if (!(vginfo = vginfo_from_vgname(vgname, vgid))) {
981 : : /*** FIXME - vginfo ends up duplicated instead of renamed.
982 : : // Renaming? This lookup fails.
983 : : if ((vginfo = vginfo_from_vgid(vgid))) {
984 : : next = vginfo->next;
985 : : old_vginfo = vginfo_from_vgname(vginfo->vgname, NULL);
986 : : if (old_vginfo == vginfo) {
987 : : dm_hash_remove(_vgname_hash, old_vginfo->vgname);
988 : : if (old_vginfo->next) {
989 : : if (!dm_hash_insert(_vgname_hash, old_vginfo->vgname, old_vginfo->next)) {
990 : : log_error("vg hash re-insertion failed: %s",
991 : : old_vginfo->vgname);
992 : : return 0;
993 : : }
994 : : }
995 : : } else do {
996 : : if (old_vginfo->next == vginfo) {
997 : : old_vginfo->next = vginfo->next;
998 : : break;
999 : : }
1000 : : } while ((old_vginfo = old_vginfo->next));
1001 : : vginfo->next = NULL;
1002 : :
1003 : : dm_free(vginfo->vgname);
1004 : : if (!(vginfo->vgname = dm_strdup(vgname))) {
1005 : : log_error("cache vgname alloc failed for %s", vgname);
1006 : : return 0;
1007 : : }
1008 : :
1009 : : // Rename so can assume new name does not already exist
1010 : : if (!dm_hash_insert(_vgname_hash, vginfo->vgname, vginfo->next)) {
1011 : : log_error("vg hash re-insertion failed: %s",
1012 : : vginfo->vgname);
1013 : : return 0;
1014 : : }
1015 : : } else {
1016 : : ***/
1017 [ - + ]: 9 : if (!(vginfo = dm_malloc(sizeof(*vginfo)))) {
1018 : 0 : log_error("lvmcache_update_vgname: list alloc failed");
1019 : 0 : return 0;
1020 : : }
1021 : 9 : memset(vginfo, 0, sizeof(*vginfo));
1022 [ - + ]: 9 : if (!(vginfo->vgname = dm_strdup(vgname))) {
1023 : 0 : dm_free(vginfo);
1024 : 0 : log_error("cache vgname alloc failed for %s", vgname);
1025 : 0 : return 0;
1026 : : }
1027 : 9 : dm_list_init(&vginfo->infos);
1028 : :
1029 : : /*
1030 : : * If we're scanning and there's an invalidated entry, remove it.
1031 : : * Otherwise we risk bogus warnings of duplicate VGs.
1032 : : */
1033 [ - + ]: 9 : while ((primary_vginfo = vginfo_from_vgname(vgname, NULL)) &&
[ # # # # ]
1034 : 0 : _scanning_in_progress && _vginfo_is_invalid(primary_vginfo))
1035 [ # # ]: 0 : dm_list_iterate_items_safe(info2, info3, &primary_vginfo->infos) {
1036 : 0 : orphan_vginfo = vginfo_from_vgname(primary_vginfo->fmt->orphan_vg_name, NULL);
1037 : 0 : _drop_vginfo(info2, primary_vginfo);
1038 : 0 : _vginfo_attach_info(orphan_vginfo, info2);
1039 [ # # ]: 0 : if (info2->mdas.n)
1040 : 0 : sprintf(mdabuf, " with %u mdas",
1041 : 0 : dm_list_size(&info2->mdas));
1042 : : else
1043 : 0 : mdabuf[0] = '\0';
1044 [ # # ][ # # ]: 0 : log_debug("lvmcache: %s: now in VG %s%s%s%s%s",
[ # # ]
1045 : : dev_name(info2->dev),
1046 : : vgname, orphan_vginfo->vgid[0] ? " (" : "",
1047 : : orphan_vginfo->vgid[0] ? orphan_vginfo->vgid : "",
1048 : : orphan_vginfo->vgid[0] ? ")" : "", mdabuf);
1049 : : }
1050 : :
1051 [ - + ]: 9 : if (!_insert_vginfo(vginfo, vgid, vgstatus, creation_host,
1052 : : primary_vginfo)) {
1053 : 0 : dm_free(vginfo->vgname);
1054 : 0 : dm_free(vginfo);
1055 : 0 : return 0;
1056 : : }
1057 : : /* Ensure orphans appear last on list_iterate */
1058 [ + - ]: 9 : if (is_orphan_vg(vgname))
1059 : 9 : dm_list_add(&_vginfos, &vginfo->list);
1060 : : else
1061 : 0 : dm_list_add_h(&_vginfos, &vginfo->list);
1062 : : /***
1063 : : }
1064 : : ***/
1065 : : }
1066 : :
1067 [ - + ]: 9 : if (info)
1068 : 0 : _vginfo_attach_info(vginfo, info);
1069 [ - + ]: 9 : else if (!_lvmcache_update_vgid(NULL, vginfo, vgid)) /* Orphans */
1070 : 0 : return_0;
1071 : :
1072 : 9 : _update_cache_vginfo_lock_state(vginfo, vgname_is_locked(vgname));
1073 : :
1074 : : /* FIXME Check consistency of list! */
1075 : 9 : vginfo->fmt = fmt;
1076 : :
1077 [ - + ]: 9 : if (info) {
1078 [ # # ]: 0 : if (info->mdas.n)
1079 : 0 : sprintf(mdabuf, " with %u mdas", dm_list_size(&info->mdas));
1080 : : else
1081 : 0 : mdabuf[0] = '\0';
1082 [ # # ][ # # ]: 0 : log_debug("lvmcache: %s: now in VG %s%s%s%s%s",
[ # # ]
1083 : : dev_name(info->dev),
1084 : : vgname, vginfo->vgid[0] ? " (" : "",
1085 : : vginfo->vgid[0] ? vginfo->vgid : "",
1086 : : vginfo->vgid[0] ? ")" : "", mdabuf);
1087 : : } else
1088 : 9 : log_debug("lvmcache: initialised VG %s", vgname);
1089 : :
1090 : 9 : return 1;
1091 : : }
1092 : :
1093 : 0 : static int _lvmcache_update_vgstatus(struct lvmcache_info *info, uint32_t vgstatus,
1094 : : const char *creation_host)
1095 : : {
1096 [ # # ][ # # ]: 0 : if (!info || !info->vginfo)
1097 : 0 : return 1;
1098 : :
1099 [ # # ]: 0 : if ((info->vginfo->status & EXPORTED_VG) != (vgstatus & EXPORTED_VG))
1100 [ # # ]: 0 : log_debug("lvmcache: %s: VG %s %s exported",
1101 : : dev_name(info->dev), info->vginfo->vgname,
1102 : : vgstatus & EXPORTED_VG ? "now" : "no longer");
1103 : :
1104 : 0 : info->vginfo->status = vgstatus;
1105 : :
1106 [ # # ]: 0 : if (!creation_host)
1107 : 0 : return 1;
1108 : :
1109 [ # # ][ # # ]: 0 : if (info->vginfo->creation_host && !strcmp(creation_host,
1110 : 0 : info->vginfo->creation_host))
1111 : 0 : return 1;
1112 : :
1113 [ # # ]: 0 : if (info->vginfo->creation_host)
1114 : 0 : dm_free(info->vginfo->creation_host);
1115 : :
1116 [ # # ]: 0 : if (!(info->vginfo->creation_host = dm_strdup(creation_host))) {
1117 : 0 : log_error("cache creation host alloc failed for %s",
1118 : : creation_host);
1119 : 0 : return 0;
1120 : : }
1121 : :
1122 : 0 : log_debug("lvmcache: %s: VG %s: Set creation host to %s.",
1123 : : dev_name(info->dev), info->vginfo->vgname, creation_host);
1124 : :
1125 : 0 : return 1;
1126 : : }
1127 : :
1128 : 9 : int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt)
1129 : : {
1130 [ + + ][ - + ]: 9 : if (!_lock_hash && !lvmcache_init()) {
1131 : 0 : log_error("Internal cache initialisation failed");
1132 : 0 : return 0;
1133 : : }
1134 : :
1135 : 9 : return _lvmcache_update_vgname(NULL, vgname, vgname, 0, "", fmt);
1136 : : }
1137 : :
1138 : 0 : int lvmcache_update_vgname_and_id(struct lvmcache_info *info,
1139 : : const char *vgname, const char *vgid,
1140 : : uint32_t vgstatus, const char *creation_host)
1141 : : {
1142 [ # # ][ # # ]: 0 : if (!vgname && !info->vginfo) {
1143 : 0 : log_error(INTERNAL_ERROR "NULL vgname handed to cache");
1144 : : /* FIXME Remove this */
1145 : 0 : vgname = info->fmt->orphan_vg_name;
1146 : 0 : vgid = vgname;
1147 : : }
1148 : :
1149 : : /* If PV without mdas is already in a real VG, don't make it orphan */
1150 [ # # ][ # # ]: 0 : if (is_orphan_vg(vgname) && info->vginfo && !dm_list_size(&info->mdas) &&
[ # # # # #
# ]
1151 : 0 : !is_orphan_vg(info->vginfo->vgname) && memlock())
1152 : 0 : return 1;
1153 : :
1154 : : /* If moving PV from orphan to real VG, always mark it valid */
1155 [ # # ]: 0 : if (!is_orphan_vg(vgname))
1156 : 0 : info->status &= ~CACHE_INVALID;
1157 : :
1158 [ # # # # # : 0 : if (!_lvmcache_update_vgname(info, vgname, vgid, vgstatus,
# ]
1159 : : creation_host, info->fmt) ||
1160 : 0 : !_lvmcache_update_vgid(info, info->vginfo, vgid) ||
1161 : 0 : !_lvmcache_update_vgstatus(info, vgstatus, creation_host))
1162 : 0 : return_0;
1163 : :
1164 : 0 : return 1;
1165 : : }
1166 : :
1167 : 0 : int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
1168 : : {
1169 : : struct pv_list *pvl;
1170 : : struct lvmcache_info *info;
1171 : : char pvid_s[ID_LEN + 1] __attribute((aligned(8)));
1172 : :
1173 : 0 : pvid_s[sizeof(pvid_s) - 1] = '\0';
1174 : :
1175 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
1176 : 0 : strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1);
1177 : : /* FIXME Could pvl->pv->dev->pvid ever be different? */
1178 [ # # # # ]: 0 : if ((info = info_from_pvid(pvid_s, 0)) &&
1179 : 0 : !lvmcache_update_vgname_and_id(info, vg->name,
1180 : : (char *) &vg->id,
1181 : 0 : vg->status, NULL))
1182 : 0 : return_0;
1183 : : }
1184 : :
1185 : : /* store text representation of vg to cache */
1186 [ # # ]: 0 : if (vg->cmd->current_settings.cache_vgmetadata)
1187 : 0 : _store_metadata(vg, precommitted);
1188 : :
1189 : 0 : return 1;
1190 : : }
1191 : :
1192 : 0 : struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
1193 : : struct device *dev,
1194 : : const char *vgname, const char *vgid,
1195 : : uint32_t vgstatus)
1196 : : {
1197 : : struct label *label;
1198 : : struct lvmcache_info *existing, *info;
1199 : : char pvid_s[ID_LEN + 1] __attribute((aligned(8)));
1200 : :
1201 [ # # ][ # # ]: 0 : if (!_vgname_hash && !lvmcache_init()) {
1202 : 0 : log_error("Internal cache initialisation failed");
1203 : 0 : return NULL;
1204 : : }
1205 : :
1206 : 0 : strncpy(pvid_s, pvid, sizeof(pvid_s));
1207 : 0 : pvid_s[sizeof(pvid_s) - 1] = '\0';
1208 : :
1209 [ # # # # ]: 0 : if (!(existing = info_from_pvid(pvid_s, 0)) &&
1210 : 0 : !(existing = info_from_pvid(dev->pvid, 0))) {
1211 [ # # ]: 0 : if (!(label = label_create(labeller)))
1212 : 0 : return_NULL;
1213 [ # # ]: 0 : if (!(info = dm_malloc(sizeof(*info)))) {
1214 : 0 : log_error("lvmcache_info allocation failed");
1215 : 0 : label_destroy(label);
1216 : 0 : return NULL;
1217 : : }
1218 : 0 : memset(info, 0, sizeof(*info));
1219 : :
1220 : 0 : label->info = info;
1221 : 0 : info->label = label;
1222 : 0 : dm_list_init(&info->list);
1223 : 0 : info->dev = dev;
1224 : : } else {
1225 [ # # ]: 0 : if (existing->dev != dev) {
1226 : : /* Is the existing entry a duplicate pvid e.g. md ? */
1227 [ # # # # ]: 0 : if (dev_subsystem_part_major(existing->dev) &&
1228 : 0 : !dev_subsystem_part_major(dev)) {
1229 : 0 : log_very_verbose("Ignoring duplicate PV %s on "
1230 : : "%s - using %s %s",
1231 : : pvid, dev_name(dev),
1232 : : dev_subsystem_name(existing->dev),
1233 : : dev_name(existing->dev));
1234 : 0 : return NULL;
1235 [ # # # # ]: 0 : } else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
1236 : 0 : !dm_is_dm_major(MAJOR(dev->dev))) {
1237 : 0 : log_very_verbose("Ignoring duplicate PV %s on "
1238 : : "%s - using dm %s",
1239 : : pvid, dev_name(dev),
1240 : : dev_name(existing->dev));
1241 : 0 : return NULL;
1242 [ # # # # ]: 0 : } else if (!dev_subsystem_part_major(existing->dev) &&
1243 : 0 : dev_subsystem_part_major(dev))
1244 : 0 : log_very_verbose("Duplicate PV %s on %s - "
1245 : : "using %s %s", pvid,
1246 : : dev_name(existing->dev),
1247 : : dev_subsystem_name(existing->dev),
1248 : : dev_name(dev));
1249 [ # # # # ]: 0 : else if (!dm_is_dm_major(MAJOR(existing->dev->dev)) &&
1250 : 0 : dm_is_dm_major(MAJOR(dev->dev)))
1251 : 0 : log_very_verbose("Duplicate PV %s on %s - "
1252 : : "using dm %s", pvid,
1253 : : dev_name(existing->dev),
1254 : : dev_name(dev));
1255 : : /* FIXME If both dm, check dependencies */
1256 : : //else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
1257 : : //dm_is_dm_major(MAJOR(dev->dev)))
1258 : : //
1259 [ # # ]: 0 : else if (!strcmp(pvid_s, existing->dev->pvid))
1260 : 0 : log_error("Found duplicate PV %s: using %s not "
1261 : : "%s", pvid, dev_name(dev),
1262 : : dev_name(existing->dev));
1263 : : }
1264 [ # # ]: 0 : if (strcmp(pvid_s, existing->dev->pvid))
1265 : 0 : log_debug("Updating pvid cache to %s (%s) from %s (%s)",
1266 : : pvid_s, dev_name(dev),
1267 : : existing->dev->pvid, dev_name(existing->dev));
1268 : : /* Switch over to new preferred device */
1269 : 0 : existing->dev = dev;
1270 : 0 : info = existing;
1271 : : /* Has labeller changed? */
1272 [ # # ]: 0 : if (info->label->labeller != labeller) {
1273 : 0 : label_destroy(info->label);
1274 [ # # ]: 0 : if (!(info->label = label_create(labeller)))
1275 : : /* FIXME leaves info without label! */
1276 : 0 : return_NULL;
1277 : 0 : info->label->info = info;
1278 : : }
1279 : 0 : label = info->label;
1280 : : }
1281 : :
1282 : 0 : info->fmt = (const struct format_type *) labeller->private;
1283 : 0 : info->status |= CACHE_INVALID;
1284 : :
1285 [ # # ]: 0 : if (!_lvmcache_update_pvid(info, pvid_s)) {
1286 [ # # ]: 0 : if (!existing) {
1287 : 0 : dm_free(info);
1288 : 0 : label_destroy(label);
1289 : : }
1290 : 0 : return NULL;
1291 : : }
1292 : :
1293 [ # # ]: 0 : if (!lvmcache_update_vgname_and_id(info, vgname, vgid, vgstatus, NULL)) {
1294 [ # # ]: 0 : if (!existing) {
1295 : 0 : dm_hash_remove(_pvid_hash, pvid_s);
1296 : 0 : strcpy(info->dev->pvid, "");
1297 : 0 : dm_free(info);
1298 : 0 : label_destroy(label);
1299 : : }
1300 : 0 : return NULL;
1301 : : }
1302 : :
1303 : 0 : return info;
1304 : : }
1305 : :
1306 : 0 : static void _lvmcache_destroy_entry(struct lvmcache_info *info)
1307 : : {
1308 : 0 : _vginfo_detach_info(info);
1309 : 0 : strcpy(info->dev->pvid, "");
1310 : 0 : label_destroy(info->label);
1311 : 0 : dm_free(info);
1312 : 0 : }
1313 : :
1314 : 9 : static void _lvmcache_destroy_vgnamelist(struct lvmcache_vginfo *vginfo)
1315 : : {
1316 : : struct lvmcache_vginfo *next;
1317 : :
1318 : : do {
1319 : 9 : next = vginfo->next;
1320 [ - + ]: 9 : if (!_free_vginfo(vginfo))
1321 : 0 : stack;
1322 [ - + ]: 9 : } while ((vginfo = next));
1323 : 9 : }
1324 : :
1325 : 0 : static void _lvmcache_destroy_lockname(struct dm_hash_node *n)
1326 : : {
1327 : : char *vgname;
1328 : :
1329 [ # # ]: 0 : if (!dm_hash_get_data(_lock_hash, n))
1330 : 0 : return;
1331 : :
1332 : 0 : vgname = dm_hash_get_key(_lock_hash, n);
1333 : :
1334 [ # # ]: 0 : if (!strcmp(vgname, VG_GLOBAL))
1335 : 0 : _vg_global_lock_held = 1;
1336 : : else
1337 : 0 : log_error(INTERNAL_ERROR "Volume Group %s was not unlocked",
1338 : : dm_hash_get_key(_lock_hash, n));
1339 : : }
1340 : :
1341 : 3 : void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans)
1342 : : {
1343 : : struct dm_hash_node *n;
1344 : 3 : log_verbose("Wiping internal VG cache");
1345 : :
1346 : 3 : _has_scanned = 0;
1347 : :
1348 [ + - ]: 3 : if (_vgid_hash) {
1349 : 3 : dm_hash_destroy(_vgid_hash);
1350 : 3 : _vgid_hash = NULL;
1351 : : }
1352 : :
1353 [ + - ]: 3 : if (_pvid_hash) {
1354 : 3 : dm_hash_iter(_pvid_hash, (dm_hash_iterate_fn) _lvmcache_destroy_entry);
1355 : 3 : dm_hash_destroy(_pvid_hash);
1356 : 3 : _pvid_hash = NULL;
1357 : : }
1358 : :
1359 [ + - ]: 3 : if (_vgname_hash) {
1360 : 3 : dm_hash_iter(_vgname_hash,
1361 : : (dm_hash_iterate_fn) _lvmcache_destroy_vgnamelist);
1362 : 3 : dm_hash_destroy(_vgname_hash);
1363 : 3 : _vgname_hash = NULL;
1364 : : }
1365 : :
1366 [ + - ]: 3 : if (_lock_hash) {
1367 [ - + ]: 3 : dm_hash_iterate(n, _lock_hash)
1368 : 0 : _lvmcache_destroy_lockname(n);
1369 : 3 : dm_hash_destroy(_lock_hash);
1370 : 3 : _lock_hash = NULL;
1371 : : }
1372 : :
1373 [ - + ]: 3 : if (!dm_list_empty(&_vginfos))
1374 : 0 : log_error(INTERNAL_ERROR "_vginfos list should be empty");
1375 : 3 : dm_list_init(&_vginfos);
1376 : :
1377 [ - + ]: 3 : if (retain_orphans)
1378 : 0 : init_lvmcache_orphans(cmd);
1379 : 3 : }
|