Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 : : * Copyright (C) 2004-2007 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 "format-text.h"
18 : : #include "import-export.h"
19 : : #include "device.h"
20 : : #include "lvm-file.h"
21 : : #include "config.h"
22 : : #include "display.h"
23 : : #include "toolcontext.h"
24 : : #include "lvm-string.h"
25 : : #include "uuid.h"
26 : : #include "layout.h"
27 : : #include "crc.h"
28 : : #include "xlate.h"
29 : : #include "label.h"
30 : : #include "memlock.h"
31 : : #include "lvmcache.h"
32 : :
33 : : #include <unistd.h>
34 : : #include <sys/file.h>
35 : : #include <sys/param.h>
36 : : #include <limits.h>
37 : : #include <dirent.h>
38 : : #include <ctype.h>
39 : :
40 : : static struct mda_header *_raw_read_mda_header(const struct format_type *fmt,
41 : : struct device_area *dev_area);
42 : :
43 : : static struct format_instance *_text_create_text_instance(const struct format_type
44 : : *fmt, const char *vgname,
45 : : const char *vgid,
46 : : void *context);
47 : :
48 : : struct text_fid_context {
49 : : char *raw_metadata_buf;
50 : : uint32_t raw_metadata_buf_size;
51 : : };
52 : :
53 : : struct dir_list {
54 : : struct dm_list list;
55 : : char dir[0];
56 : : };
57 : :
58 : : struct raw_list {
59 : : struct dm_list list;
60 : : struct device_area dev_area;
61 : : };
62 : :
63 : : struct text_context {
64 : : char *path_live; /* Path to file holding live metadata */
65 : : char *path_edit; /* Path to file holding edited metadata */
66 : : char *desc; /* Description placed inside file */
67 : : };
68 : :
69 : : /*
70 : : * NOTE: Currently there can be only one vg per text file.
71 : : */
72 : :
73 : 0 : static int _text_vg_setup(struct format_instance *fid __attribute((unused)),
74 : : struct volume_group *vg)
75 : : {
76 [ # # ]: 0 : if (vg->extent_size & (vg->extent_size - 1)) {
77 : 0 : log_error("Extent size must be power of 2");
78 : 0 : return 0;
79 : : }
80 : :
81 : 0 : return 1;
82 : : }
83 : :
84 : 0 : static uint64_t _mda_free_sectors_raw(struct metadata_area *mda)
85 : : {
86 : 0 : struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
87 : :
88 : 0 : return mdac->free_sectors;
89 : : }
90 : :
91 : 0 : static uint64_t _mda_total_sectors_raw(struct metadata_area *mda)
92 : : {
93 : 0 : struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
94 : :
95 : 0 : return mdac->area.size >> SECTOR_SHIFT;
96 : : }
97 : :
98 : : /*
99 : : * Check if metadata area belongs to vg
100 : : */
101 : 0 : static int _mda_in_vg_raw(struct format_instance *fid __attribute((unused)),
102 : : struct volume_group *vg, struct metadata_area *mda)
103 : : {
104 : 0 : struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
105 : : struct pv_list *pvl;
106 : :
107 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs)
108 [ # # ]: 0 : if (pvl->pv->dev == mdac->area.dev)
109 : 0 : return 1;
110 : :
111 : 0 : return 0;
112 : : }
113 : :
114 : : /*
115 : : * For circular region between region_start and region_start + region_size,
116 : : * back up one SECTOR_SIZE from 'region_ptr' and return the value.
117 : : * This allows reverse traversal through text metadata area to find old
118 : : * metadata.
119 : : *
120 : : * Parameters:
121 : : * region_start: start of the region (bytes)
122 : : * region_size: size of the region (bytes)
123 : : * region_ptr: pointer within the region (bytes)
124 : : * NOTE: region_start <= region_ptr <= region_start + region_size
125 : : */
126 : 0 : static uint64_t _get_prev_sector_circular(uint64_t region_start,
127 : : uint64_t region_size,
128 : : uint64_t region_ptr)
129 : : {
130 [ # # ]: 0 : if (region_ptr >= region_start + SECTOR_SIZE)
131 : 0 : return region_ptr - SECTOR_SIZE;
132 : : else
133 : 0 : return (region_start + region_size - SECTOR_SIZE);
134 : : }
135 : :
136 : : /*
137 : : * Analyze a metadata area for old metadata records in the circular buffer.
138 : : * This function just looks through and makes a first pass at the data in
139 : : * the sectors for particular things.
140 : : * FIXME: do something with each metadata area (try to extract vg, write
141 : : * raw data to file, etc)
142 : : */
143 : 0 : static int _pv_analyze_mda_raw (const struct format_type * fmt,
144 : : struct metadata_area *mda)
145 : : {
146 : : struct mda_header *mdah;
147 : : struct raw_locn *rlocn;
148 : : uint64_t area_start;
149 : : uint64_t area_size;
150 : : uint64_t prev_sector, prev_sector2;
151 : : uint64_t latest_mrec_offset;
152 : : int i;
153 : : uint64_t offset;
154 : : uint64_t offset2;
155 : : size_t size;
156 : : size_t size2;
157 : 0 : char *buf=NULL;
158 : : struct device_area *area;
159 : : struct mda_context *mdac;
160 : 0 : int r=0;
161 : :
162 : 0 : mdac = (struct mda_context *) mda->metadata_locn;
163 : :
164 : 0 : log_print("Found text metadata area: offset=%" PRIu64 ", size=%"
165 : : PRIu64, mdac->area.start, mdac->area.size);
166 : 0 : area = &mdac->area;
167 : :
168 [ # # ]: 0 : if (!dev_open(area->dev))
169 : 0 : return_0;
170 : :
171 [ # # ]: 0 : if (!(mdah = _raw_read_mda_header(fmt, area)))
172 : 0 : goto_out;
173 : :
174 : 0 : rlocn = mdah->raw_locns;
175 : :
176 : : /*
177 : : * The device area includes the metadata header as well as the
178 : : * records, so remove the metadata header from the start and size
179 : : */
180 : 0 : area_start = area->start + MDA_HEADER_SIZE;
181 : 0 : area_size = area->size - MDA_HEADER_SIZE;
182 : 0 : latest_mrec_offset = rlocn->offset + area->start;
183 : :
184 : : /*
185 : : * Start searching at rlocn (point of live metadata) and go
186 : : * backwards.
187 : : */
188 : 0 : prev_sector = _get_prev_sector_circular(area_start, area_size,
189 : : latest_mrec_offset);
190 : 0 : offset = prev_sector;
191 : 0 : size = SECTOR_SIZE;
192 : 0 : offset2 = size2 = 0;
193 : 0 : i = 0;
194 [ # # ]: 0 : while (prev_sector != latest_mrec_offset) {
195 : 0 : prev_sector2 = prev_sector;
196 : 0 : prev_sector = _get_prev_sector_circular(area_start, area_size,
197 : : prev_sector);
198 [ # # ]: 0 : if (prev_sector > prev_sector2)
199 : 0 : goto_out;
200 : : /*
201 : : * FIXME: for some reason, the whole metadata region from
202 : : * area->start to area->start+area->size is not used.
203 : : * Only ~32KB seems to contain valid metadata records
204 : : * (LVM2 format - format_text). As a result, I end up with
205 : : * "maybe_config_section" returning true when there's no valid
206 : : * metadata in a sector (sectors with all nulls).
207 : : */
208 [ # # ]: 0 : if (!(buf = dm_pool_alloc(fmt->cmd->mem, size + size2)))
209 : 0 : goto_out;
210 : :
211 [ # # ]: 0 : if (!dev_read_circular(area->dev, offset, size,
212 : : offset2, size2, buf))
213 : 0 : goto_out;
214 : :
215 : : /*
216 : : * FIXME: We could add more sophisticated metadata detection
217 : : */
218 [ # # ]: 0 : if (maybe_config_section(buf, size + size2)) {
219 : : /* FIXME: Validate region, pull out timestamp?, etc */
220 : : /* FIXME: Do something with this region */
221 : 0 : log_verbose ("Found LVM2 metadata record at "
222 : : "offset=%"PRIu64", size=%"PRIsize_t", "
223 : : "offset2=%"PRIu64" size2=%"PRIsize_t,
224 : : offset, size, offset2, size2);
225 : 0 : offset = prev_sector;
226 : 0 : size = SECTOR_SIZE;
227 : 0 : offset2 = size2 = 0;
228 : : } else {
229 : : /*
230 : : * Not a complete metadata record, assume we have
231 : : * metadata and just increase the size and offset.
232 : : * Start the second region if the previous sector is
233 : : * wrapping around towards the end of the disk.
234 : : */
235 [ # # ]: 0 : if (prev_sector > offset) {
236 : 0 : offset2 = prev_sector;
237 : 0 : size2 += SECTOR_SIZE;
238 : : } else {
239 : 0 : offset = prev_sector;
240 : 0 : size += SECTOR_SIZE;
241 : : }
242 : : }
243 : 0 : dm_pool_free(fmt->cmd->mem, buf);
244 : 0 : buf = NULL;
245 : : }
246 : :
247 : 0 : r = 1;
248 : : out:
249 [ # # ]: 0 : if (buf)
250 : 0 : dm_pool_free(fmt->cmd->mem, buf);
251 [ # # ]: 0 : if (!dev_close(area->dev))
252 : 0 : stack;
253 : 0 : return r;
254 : : }
255 : :
256 : :
257 : :
258 : 0 : static int _text_lv_setup(struct format_instance *fid __attribute((unused)),
259 : : struct logical_volume *lv)
260 : : {
261 : : /******** FIXME Any LV size restriction?
262 : : uint64_t max_size = UINT_MAX;
263 : :
264 : : if (lv->size > max_size) {
265 : : char *dummy = display_size(max_size);
266 : : log_error("logical volumes cannot be larger than %s", dummy);
267 : : dm_free(dummy);
268 : : return 0;
269 : : }
270 : : */
271 : :
272 [ # # ][ # # ]: 0 : if (!*lv->lvid.s && !lvid_create(&lv->lvid, &lv->vg->id)) {
273 : 0 : log_error("Random lvid creation failed for %s/%s.",
274 : : lv->vg->name, lv->name);
275 : 0 : return 0;
276 : : }
277 : :
278 : 0 : return 1;
279 : : }
280 : :
281 : 0 : static void _xlate_mdah(struct mda_header *mdah)
282 : : {
283 : : struct raw_locn *rl;
284 : :
285 : 0 : mdah->version = xlate32(mdah->version);
286 : 0 : mdah->start = xlate64(mdah->start);
287 : 0 : mdah->size = xlate64(mdah->size);
288 : :
289 : 0 : rl = &mdah->raw_locns[0];
290 [ # # ]: 0 : while (rl->offset) {
291 : 0 : rl->checksum = xlate32(rl->checksum);
292 : 0 : rl->offset = xlate64(rl->offset);
293 : 0 : rl->size = xlate64(rl->size);
294 : 0 : rl++;
295 : : }
296 : 0 : }
297 : :
298 : 0 : static struct mda_header *_raw_read_mda_header(const struct format_type *fmt,
299 : : struct device_area *dev_area)
300 : : {
301 : : struct mda_header *mdah;
302 : :
303 [ # # ]: 0 : if (!(mdah = dm_pool_alloc(fmt->cmd->mem, MDA_HEADER_SIZE))) {
304 : 0 : log_error("struct mda_header allocation failed");
305 : 0 : return NULL;
306 : : }
307 : :
308 [ # # ]: 0 : if (!dev_read(dev_area->dev, dev_area->start, MDA_HEADER_SIZE, mdah))
309 : 0 : goto_bad;
310 : :
311 [ # # ]: 0 : if (mdah->checksum_xl != xlate32(calc_crc(INITIAL_CRC, mdah->magic,
312 : : MDA_HEADER_SIZE -
313 : : sizeof(mdah->checksum_xl)))) {
314 : 0 : log_error("Incorrect metadata area header checksum");
315 : 0 : goto bad;
316 : : }
317 : :
318 : 0 : _xlate_mdah(mdah);
319 : :
320 [ # # ]: 0 : if (strncmp((char *)mdah->magic, FMTT_MAGIC, sizeof(mdah->magic))) {
321 : 0 : log_error("Wrong magic number in metadata area header");
322 : 0 : goto bad;
323 : : }
324 : :
325 [ # # ]: 0 : if (mdah->version != FMTT_VERSION) {
326 : 0 : log_error("Incompatible metadata area header version: %d",
327 : : mdah->version);
328 : 0 : goto bad;
329 : : }
330 : :
331 [ # # ]: 0 : if (mdah->start != dev_area->start) {
332 : 0 : log_error("Incorrect start sector in metadata area header: %"
333 : : PRIu64, mdah->start);
334 : 0 : goto bad;
335 : : }
336 : :
337 : 0 : return mdah;
338 : :
339 : : bad:
340 : 0 : dm_pool_free(fmt->cmd->mem, mdah);
341 : 0 : return NULL;
342 : : }
343 : :
344 : 0 : static int _raw_write_mda_header(const struct format_type *fmt,
345 : : struct device *dev,
346 : : uint64_t start_byte, struct mda_header *mdah)
347 : : {
348 : 0 : strncpy((char *)mdah->magic, FMTT_MAGIC, sizeof(mdah->magic));
349 : 0 : mdah->version = FMTT_VERSION;
350 : 0 : mdah->start = start_byte;
351 : :
352 : 0 : _xlate_mdah(mdah);
353 : 0 : mdah->checksum_xl = xlate32(calc_crc(INITIAL_CRC, mdah->magic,
354 : : MDA_HEADER_SIZE -
355 : : sizeof(mdah->checksum_xl)));
356 : :
357 [ # # ]: 0 : if (!dev_write(dev, start_byte, MDA_HEADER_SIZE, mdah))
358 : 0 : return_0;
359 : :
360 : 0 : return 1;
361 : : }
362 : :
363 : 0 : static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
364 : : struct mda_header *mdah,
365 : : const char *vgname,
366 : : int *precommitted)
367 : : {
368 : : size_t len;
369 : : char vgnamebuf[NAME_LEN + 2] __attribute((aligned(8)));
370 : : struct raw_locn *rlocn, *rlocn_precommitted;
371 : : struct lvmcache_info *info;
372 : :
373 : 0 : rlocn = mdah->raw_locns; /* Slot 0 */
374 : 0 : rlocn_precommitted = rlocn + 1; /* Slot 1 */
375 : :
376 : : /* Should we use precommitted metadata? */
377 [ # # ][ # # ]: 0 : if (*precommitted && rlocn_precommitted->size &&
[ # # ]
378 : 0 : (rlocn_precommitted->offset != rlocn->offset)) {
379 : 0 : rlocn = rlocn_precommitted;
380 : : } else
381 : 0 : *precommitted = 0;
382 : :
383 : : /* FIXME Loop through rlocns two-at-a-time. List null-terminated. */
384 : : /* FIXME Ignore if checksum incorrect!!! */
385 [ # # ]: 0 : if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
386 : : sizeof(vgnamebuf), vgnamebuf))
387 : 0 : goto_bad;
388 : :
389 [ # # # # ]: 0 : if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
[ # # ]
390 : 0 : (isspace(vgnamebuf[len]) || vgnamebuf[len] == '{')) {
391 : 0 : return rlocn;
392 : : }
393 : :
394 : : bad:
395 [ # # ]: 0 : if ((info = info_from_pvid(dev_area->dev->pvid, 0)))
396 : 0 : lvmcache_update_vgname_and_id(info, FMT_TEXT_ORPHAN_VG_NAME,
397 : : FMT_TEXT_ORPHAN_VG_NAME, 0, NULL);
398 : :
399 : 0 : return NULL;
400 : : }
401 : :
402 : : /*
403 : : * Determine offset for uncommitted metadata
404 : : */
405 : 0 : static uint64_t _next_rlocn_offset(struct raw_locn *rlocn,
406 : : struct mda_header *mdah)
407 : : {
408 [ # # ]: 0 : if (!rlocn)
409 : : /* Find an empty slot */
410 : : /* FIXME Assume only one VG per mdah for now */
411 : 0 : return MDA_HEADER_SIZE;
412 : :
413 : : /* Start of free space - round up to next sector; circular */
414 : 0 : return ((rlocn->offset + rlocn->size +
415 : 0 : (SECTOR_SIZE - rlocn->size % SECTOR_SIZE) -
416 : 0 : MDA_HEADER_SIZE) % (mdah->size - MDA_HEADER_SIZE))
417 : : + MDA_HEADER_SIZE;
418 : : }
419 : :
420 : 0 : static int _raw_holds_vgname(struct format_instance *fid,
421 : : struct device_area *dev_area, const char *vgname)
422 : : {
423 : 0 : int r = 0;
424 : 0 : int noprecommit = 0;
425 : : struct mda_header *mdah;
426 : :
427 [ # # ]: 0 : if (!dev_open(dev_area->dev))
428 : 0 : return_0;
429 : :
430 [ # # ]: 0 : if (!(mdah = _raw_read_mda_header(fid->fmt, dev_area)))
431 : 0 : return_0;
432 : :
433 [ # # ]: 0 : if (_find_vg_rlocn(dev_area, mdah, vgname, &noprecommit))
434 : 0 : r = 1;
435 : :
436 [ # # ]: 0 : if (!dev_close(dev_area->dev))
437 : 0 : stack;
438 : :
439 : 0 : return r;
440 : : }
441 : :
442 : 0 : static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
443 : : const char *vgname,
444 : : struct device_area *area,
445 : : int precommitted)
446 : : {
447 : 0 : struct volume_group *vg = NULL;
448 : : struct raw_locn *rlocn;
449 : : struct mda_header *mdah;
450 : : time_t when;
451 : : char *desc;
452 : 0 : uint32_t wrap = 0;
453 : :
454 [ # # ]: 0 : if (!dev_open(area->dev))
455 : 0 : return_NULL;
456 : :
457 [ # # ]: 0 : if (!(mdah = _raw_read_mda_header(fid->fmt, area)))
458 : 0 : goto_out;
459 : :
460 [ # # ]: 0 : if (!(rlocn = _find_vg_rlocn(area, mdah, vgname, &precommitted))) {
461 : 0 : log_debug("VG %s not found on %s", vgname, dev_name(area->dev));
462 : 0 : goto out;
463 : : }
464 : :
465 [ # # ]: 0 : if (rlocn->offset + rlocn->size > mdah->size)
466 : 0 : wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size);
467 : :
468 [ # # ]: 0 : if (wrap > rlocn->offset) {
469 : 0 : log_error("VG %s metadata too large for circular buffer",
470 : : vg->name);
471 : 0 : goto out;
472 : : }
473 : :
474 : : /* FIXME 64-bit */
475 [ # # ]: 0 : if (!(vg = text_vg_import_fd(fid, NULL, area->dev,
476 : 0 : (off_t) (area->start + rlocn->offset),
477 : : (uint32_t) (rlocn->size - wrap),
478 : 0 : (off_t) (area->start + MDA_HEADER_SIZE),
479 : : wrap, calc_crc, rlocn->checksum, &when,
480 : : &desc)))
481 : 0 : goto_out;
482 [ # # ]: 0 : log_debug("Read %s %smetadata (%u) from %s at %" PRIu64 " size %"
483 : : PRIu64, vg->name, precommitted ? "pre-commit " : "",
484 : : vg->seqno, dev_name(area->dev),
485 : : area->start + rlocn->offset, rlocn->size);
486 : :
487 [ # # ]: 0 : if (precommitted)
488 : 0 : vg->status |= PRECOMMITTED;
489 : :
490 : : out:
491 [ # # ]: 0 : if (!dev_close(area->dev))
492 : 0 : stack;
493 : :
494 : 0 : return vg;
495 : : }
496 : :
497 : 0 : static struct volume_group *_vg_read_raw(struct format_instance *fid,
498 : : const char *vgname,
499 : : struct metadata_area *mda)
500 : : {
501 : 0 : struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
502 : :
503 : 0 : return _vg_read_raw_area(fid, vgname, &mdac->area, 0);
504 : : }
505 : :
506 : 0 : static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
507 : : const char *vgname,
508 : : struct metadata_area *mda)
509 : : {
510 : 0 : struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
511 : :
512 : 0 : return _vg_read_raw_area(fid, vgname, &mdac->area, 1);
513 : : }
514 : :
515 : 0 : static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
516 : : struct metadata_area *mda)
517 : : {
518 : 0 : struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
519 : 0 : struct text_fid_context *fidtc = (struct text_fid_context *) fid->private;
520 : : struct raw_locn *rlocn;
521 : : struct mda_header *mdah;
522 : : struct pv_list *pvl;
523 : 0 : int r = 0;
524 : 0 : uint64_t new_wrap = 0, old_wrap = 0, new_end;
525 : 0 : int found = 0;
526 : 0 : int noprecommit = 0;
527 : :
528 : : /* Ignore any mda on a PV outside the VG. vgsplit relies on this */
529 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
530 [ # # ]: 0 : if (pvl->pv->dev == mdac->area.dev) {
531 : 0 : found = 1;
532 : 0 : break;
533 : : }
534 : : }
535 : :
536 [ # # ]: 0 : if (!found)
537 : 0 : return 1;
538 : :
539 [ # # ]: 0 : if (!dev_open(mdac->area.dev))
540 : 0 : return_0;
541 : :
542 [ # # ]: 0 : if (!(mdah = _raw_read_mda_header(fid->fmt, &mdac->area)))
543 : 0 : goto_out;
544 : :
545 : 0 : rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, &noprecommit);
546 : 0 : mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah);
547 : :
548 [ # # # # ]: 0 : if (!fidtc->raw_metadata_buf &&
549 : 0 : !(fidtc->raw_metadata_buf_size =
550 : 0 : text_vg_export_raw(vg, "", &fidtc->raw_metadata_buf))) {
551 : 0 : log_error("VG %s metadata writing failed", vg->name);
552 : 0 : goto out;
553 : : }
554 : :
555 : 0 : mdac->rlocn.size = fidtc->raw_metadata_buf_size;
556 : :
557 [ # # ]: 0 : if (mdac->rlocn.offset + mdac->rlocn.size > mdah->size)
558 : 0 : new_wrap = (mdac->rlocn.offset + mdac->rlocn.size) - mdah->size;
559 : :
560 [ # # ][ # # ]: 0 : if (rlocn && (rlocn->offset + rlocn->size > mdah->size))
561 : 0 : old_wrap = (rlocn->offset + rlocn->size) - mdah->size;
562 : :
563 [ # # ]: 0 : new_end = new_wrap ? new_wrap + MDA_HEADER_SIZE :
564 : 0 : mdac->rlocn.offset + mdac->rlocn.size;
565 : :
566 [ # # ][ # # ]: 0 : if ((new_wrap && old_wrap) ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
567 : 0 : (rlocn && (new_wrap || old_wrap) && (new_end > rlocn->offset)) ||
568 : 0 : (mdac->rlocn.size >= mdah->size)) {
569 : 0 : log_error("VG %s metadata too large for circular buffer",
570 : : vg->name);
571 : 0 : goto out;
572 : : }
573 : :
574 : 0 : log_debug("Writing %s metadata to %s at %" PRIu64 " len %" PRIu64,
575 : : vg->name, dev_name(mdac->area.dev), mdac->area.start +
576 : : mdac->rlocn.offset, mdac->rlocn.size - new_wrap);
577 : :
578 : : /* Write text out, circularly */
579 [ # # ]: 0 : if (!dev_write(mdac->area.dev, mdac->area.start + mdac->rlocn.offset,
580 : : (size_t) (mdac->rlocn.size - new_wrap),
581 : 0 : fidtc->raw_metadata_buf))
582 : 0 : goto_out;
583 : :
584 [ # # ]: 0 : if (new_wrap) {
585 : 0 : log_debug("Writing metadata to %s at %" PRIu64 " len %" PRIu64,
586 : : dev_name(mdac->area.dev), mdac->area.start +
587 : : MDA_HEADER_SIZE, new_wrap);
588 : :
589 [ # # ]: 0 : if (!dev_write(mdac->area.dev,
590 : : mdac->area.start + MDA_HEADER_SIZE,
591 : : (size_t) new_wrap,
592 : 0 : fidtc->raw_metadata_buf +
593 : : mdac->rlocn.size - new_wrap))
594 : 0 : goto_out;
595 : : }
596 : :
597 : 0 : mdac->rlocn.checksum = calc_crc(INITIAL_CRC, fidtc->raw_metadata_buf,
598 : : (uint32_t) (mdac->rlocn.size -
599 : : new_wrap));
600 [ # # ]: 0 : if (new_wrap)
601 : 0 : mdac->rlocn.checksum = calc_crc(mdac->rlocn.checksum,
602 : 0 : fidtc->raw_metadata_buf +
603 : : mdac->rlocn.size -
604 : : new_wrap, (uint32_t) new_wrap);
605 : :
606 : 0 : r = 1;
607 : :
608 : : out:
609 [ # # ]: 0 : if (!r) {
610 [ # # ]: 0 : if (!dev_close(mdac->area.dev))
611 : 0 : stack;
612 : :
613 [ # # ]: 0 : if (fidtc->raw_metadata_buf) {
614 : 0 : dm_free(fidtc->raw_metadata_buf);
615 : 0 : fidtc->raw_metadata_buf = NULL;
616 : : }
617 : : }
618 : :
619 : 0 : return r;
620 : : }
621 : :
622 : 0 : static int _vg_commit_raw_rlocn(struct format_instance *fid,
623 : : struct volume_group *vg,
624 : : struct metadata_area *mda,
625 : : int precommit)
626 : : {
627 : 0 : struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
628 : 0 : struct text_fid_context *fidtc = (struct text_fid_context *) fid->private;
629 : : struct mda_header *mdah;
630 : : struct raw_locn *rlocn;
631 : : struct pv_list *pvl;
632 : 0 : int r = 0;
633 : 0 : int found = 0;
634 : 0 : int noprecommit = 0;
635 : :
636 : : /* Ignore any mda on a PV outside the VG. vgsplit relies on this */
637 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
638 [ # # ]: 0 : if (pvl->pv->dev == mdac->area.dev) {
639 : 0 : found = 1;
640 : 0 : break;
641 : : }
642 : : }
643 : :
644 [ # # ]: 0 : if (!found)
645 : 0 : return 1;
646 : :
647 [ # # ]: 0 : if (!(mdah = _raw_read_mda_header(fid->fmt, &mdac->area)))
648 : 0 : goto_out;
649 : :
650 [ # # ]: 0 : if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, &noprecommit))) {
651 : 0 : mdah->raw_locns[0].offset = 0;
652 : 0 : mdah->raw_locns[0].size = 0;
653 : 0 : mdah->raw_locns[0].checksum = 0;
654 : 0 : mdah->raw_locns[1].offset = 0;
655 : 0 : mdah->raw_locns[1].size = 0;
656 : 0 : mdah->raw_locns[1].checksum = 0;
657 : 0 : mdah->raw_locns[2].offset = 0;
658 : 0 : mdah->raw_locns[2].size = 0;
659 : 0 : mdah->raw_locns[2].checksum = 0;
660 : 0 : rlocn = &mdah->raw_locns[0];
661 : : }
662 : :
663 [ # # ]: 0 : if (precommit)
664 : 0 : rlocn++;
665 : : else {
666 : : /* If not precommitting, wipe the precommitted rlocn */
667 : 0 : mdah->raw_locns[1].offset = 0;
668 : 0 : mdah->raw_locns[1].size = 0;
669 : 0 : mdah->raw_locns[1].checksum = 0;
670 : : }
671 : :
672 : : /* Is there new metadata to commit? */
673 [ # # ]: 0 : if (mdac->rlocn.size) {
674 : 0 : rlocn->offset = mdac->rlocn.offset;
675 : 0 : rlocn->size = mdac->rlocn.size;
676 : 0 : rlocn->checksum = mdac->rlocn.checksum;
677 [ # # ]: 0 : log_debug("%sCommitting %s metadata (%u) to %s header at %"
678 : : PRIu64, precommit ? "Pre-" : "", vg->name, vg->seqno,
679 : : dev_name(mdac->area.dev), mdac->area.start);
680 : : } else
681 : 0 : log_debug("Wiping pre-committed %s metadata from %s "
682 : : "header at %" PRIu64, vg->name,
683 : : dev_name(mdac->area.dev), mdac->area.start);
684 : :
685 [ # # ]: 0 : if (!_raw_write_mda_header(fid->fmt, mdac->area.dev, mdac->area.start,
686 : : mdah)) {
687 : 0 : dm_pool_free(fid->fmt->cmd->mem, mdah);
688 : 0 : log_error("Failed to write metadata area header");
689 : 0 : goto out;
690 : : }
691 : :
692 : 0 : r = 1;
693 : :
694 : : out:
695 [ # # ]: 0 : if (!precommit) {
696 [ # # ]: 0 : if (!dev_close(mdac->area.dev))
697 : 0 : stack;
698 [ # # ]: 0 : if (fidtc->raw_metadata_buf) {
699 : 0 : dm_free(fidtc->raw_metadata_buf);
700 : 0 : fidtc->raw_metadata_buf = NULL;
701 : : }
702 : : }
703 : :
704 : 0 : return r;
705 : : }
706 : :
707 : 0 : static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
708 : : struct metadata_area *mda)
709 : : {
710 : 0 : return _vg_commit_raw_rlocn(fid, vg, mda, 0);
711 : : }
712 : :
713 : 0 : static int _vg_precommit_raw(struct format_instance *fid,
714 : : struct volume_group *vg,
715 : : struct metadata_area *mda)
716 : : {
717 : 0 : return _vg_commit_raw_rlocn(fid, vg, mda, 1);
718 : : }
719 : :
720 : : /* Close metadata area devices */
721 : 0 : static int _vg_revert_raw(struct format_instance *fid, struct volume_group *vg,
722 : : struct metadata_area *mda)
723 : : {
724 : 0 : struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
725 : : struct pv_list *pvl;
726 : 0 : int found = 0;
727 : :
728 : : /* Ignore any mda on a PV outside the VG. vgsplit relies on this */
729 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
730 [ # # ]: 0 : if (pvl->pv->dev == mdac->area.dev) {
731 : 0 : found = 1;
732 : 0 : break;
733 : : }
734 : : }
735 : :
736 [ # # ]: 0 : if (!found)
737 : 0 : return 1;
738 : :
739 : : /* Wipe pre-committed metadata */
740 : 0 : mdac->rlocn.size = 0;
741 : 0 : return _vg_commit_raw_rlocn(fid, vg, mda, 0);
742 : : }
743 : :
744 : 0 : static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
745 : : struct metadata_area *mda)
746 : : {
747 : 0 : struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
748 : : struct mda_header *mdah;
749 : : struct raw_locn *rlocn;
750 : 0 : int r = 0;
751 : 0 : int noprecommit = 0;
752 : :
753 [ # # ]: 0 : if (!dev_open(mdac->area.dev))
754 : 0 : return_0;
755 : :
756 [ # # ]: 0 : if (!(mdah = _raw_read_mda_header(fid->fmt, &mdac->area)))
757 : 0 : goto_out;
758 : :
759 [ # # ]: 0 : if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, &noprecommit))) {
760 : 0 : rlocn = &mdah->raw_locns[0];
761 : 0 : mdah->raw_locns[1].offset = 0;
762 : : }
763 : :
764 : 0 : rlocn->offset = 0;
765 : 0 : rlocn->size = 0;
766 : 0 : rlocn->checksum = 0;
767 : :
768 [ # # ]: 0 : if (!_raw_write_mda_header(fid->fmt, mdac->area.dev, mdac->area.start,
769 : : mdah)) {
770 : 0 : dm_pool_free(fid->fmt->cmd->mem, mdah);
771 : 0 : log_error("Failed to write metadata area header");
772 : 0 : goto out;
773 : : }
774 : :
775 : 0 : r = 1;
776 : :
777 : : out:
778 [ # # ]: 0 : if (!dev_close(mdac->area.dev))
779 : 0 : stack;
780 : :
781 : 0 : return r;
782 : : }
783 : :
784 : 0 : static struct volume_group *_vg_read_file_name(struct format_instance *fid,
785 : : const char *vgname,
786 : : const char *read_path)
787 : : {
788 : : struct volume_group *vg;
789 : : time_t when;
790 : : char *desc;
791 : :
792 [ # # ]: 0 : if (!(vg = text_vg_import_file(fid, read_path, &when, &desc)))
793 : 0 : return_NULL;
794 : :
795 : : /*
796 : : * Currently you can only have a single volume group per
797 : : * text file (this restriction may remain). We need to
798 : : * check that it contains the correct volume group.
799 : : */
800 [ # # ][ # # ]: 0 : if (vgname && strcmp(vgname, vg->name)) {
801 : 0 : dm_pool_free(fid->fmt->cmd->mem, vg);
802 : 0 : log_error("'%s' does not contain volume group '%s'.",
803 : : read_path, vgname);
804 : 0 : return NULL;
805 : : } else
806 : 0 : log_debug("Read volume group %s from %s", vg->name, read_path);
807 : :
808 : 0 : return vg;
809 : : }
810 : :
811 : 0 : static struct volume_group *_vg_read_file(struct format_instance *fid,
812 : : const char *vgname,
813 : : struct metadata_area *mda)
814 : : {
815 : 0 : struct text_context *tc = (struct text_context *) mda->metadata_locn;
816 : :
817 : 0 : return _vg_read_file_name(fid, vgname, tc->path_live);
818 : : }
819 : :
820 : 0 : static struct volume_group *_vg_read_precommit_file(struct format_instance *fid,
821 : : const char *vgname,
822 : : struct metadata_area *mda)
823 : : {
824 : 0 : struct text_context *tc = (struct text_context *) mda->metadata_locn;
825 : : struct volume_group *vg;
826 : :
827 [ # # ]: 0 : if ((vg = _vg_read_file_name(fid, vgname, tc->path_edit)))
828 : 0 : vg->status |= PRECOMMITTED;
829 : : else
830 : 0 : vg = _vg_read_file_name(fid, vgname, tc->path_live);
831 : :
832 : 0 : return vg;
833 : : }
834 : :
835 : 0 : static int _vg_write_file(struct format_instance *fid __attribute((unused)),
836 : : struct volume_group *vg, struct metadata_area *mda)
837 : : {
838 : 0 : struct text_context *tc = (struct text_context *) mda->metadata_locn;
839 : :
840 : : FILE *fp;
841 : : int fd;
842 : : char *slash;
843 : : char temp_file[PATH_MAX], temp_dir[PATH_MAX];
844 : :
845 : 0 : slash = strrchr(tc->path_edit, '/');
846 : :
847 [ # # ]: 0 : if (slash == 0)
848 : 0 : strcpy(temp_dir, ".");
849 [ # # ]: 0 : else if (slash - tc->path_edit < PATH_MAX) {
850 : 0 : strncpy(temp_dir, tc->path_edit,
851 : 0 : (size_t) (slash - tc->path_edit));
852 : 0 : temp_dir[slash - tc->path_edit] = '\0';
853 : :
854 : : } else {
855 : 0 : log_error("Text format failed to determine directory.");
856 : 0 : return 0;
857 : : }
858 : :
859 [ # # ]: 0 : if (!create_temp_name(temp_dir, temp_file, sizeof(temp_file), &fd,
860 : 0 : &vg->cmd->rand_seed)) {
861 : 0 : log_error("Couldn't create temporary text file name.");
862 : 0 : return 0;
863 : : }
864 : :
865 [ # # ]: 0 : if (!(fp = fdopen(fd, "w"))) {
866 : 0 : log_sys_error("fdopen", temp_file);
867 [ # # ]: 0 : if (close(fd))
868 : 0 : log_sys_error("fclose", temp_file);
869 : 0 : return 0;
870 : : }
871 : :
872 : 0 : log_debug("Writing %s metadata to %s", vg->name, temp_file);
873 : :
874 [ # # ]: 0 : if (!text_vg_export_file(vg, tc->desc, fp)) {
875 : 0 : log_error("Failed to write metadata to %s.", temp_file);
876 [ # # ]: 0 : if (fclose(fp))
877 : 0 : log_sys_error("fclose", temp_file);
878 : 0 : return 0;
879 : : }
880 : :
881 [ # # ][ # # ]: 0 : if (fsync(fd) && (errno != EROFS) && (errno != EINVAL)) {
[ # # ]
882 : 0 : log_sys_error("fsync", tc->path_edit);
883 [ # # ]: 0 : if (fclose(fp))
884 : 0 : log_sys_error("fclose", tc->path_edit);
885 : 0 : return 0;
886 : : }
887 : :
888 [ # # ]: 0 : if (lvm_fclose(fp, tc->path_edit))
889 : 0 : return_0;
890 : :
891 [ # # ]: 0 : if (rename(temp_file, tc->path_edit)) {
892 : 0 : log_debug("Renaming %s to %s", temp_file, tc->path_edit);
893 : 0 : log_error("%s: rename to %s failed: %s", temp_file,
894 : : tc->path_edit, strerror(errno));
895 : 0 : return 0;
896 : : }
897 : :
898 : 0 : return 1;
899 : : }
900 : :
901 : 0 : static int _vg_commit_file_backup(struct format_instance *fid __attribute((unused)),
902 : : struct volume_group *vg,
903 : : struct metadata_area *mda)
904 : : {
905 : 0 : struct text_context *tc = (struct text_context *) mda->metadata_locn;
906 : :
907 [ # # ]: 0 : if (test_mode()) {
908 : 0 : log_verbose("Test mode: Skipping committing %s metadata (%u)",
909 : : vg->name, vg->seqno);
910 [ # # ]: 0 : if (unlink(tc->path_edit)) {
911 : 0 : log_debug("Unlinking %s", tc->path_edit);
912 : 0 : log_sys_error("unlink", tc->path_edit);
913 : 0 : return 0;
914 : : }
915 : : } else {
916 : 0 : log_debug("Committing %s metadata (%u)", vg->name, vg->seqno);
917 : 0 : log_debug("Renaming %s to %s", tc->path_edit, tc->path_live);
918 [ # # ]: 0 : if (rename(tc->path_edit, tc->path_live)) {
919 : 0 : log_error("%s: rename to %s failed: %s", tc->path_edit,
920 : : tc->path_live, strerror(errno));
921 : 0 : return 0;
922 : : }
923 : : }
924 : :
925 : 0 : sync_dir(tc->path_edit);
926 : :
927 : 0 : return 1;
928 : : }
929 : :
930 : 0 : static int _vg_commit_file(struct format_instance *fid, struct volume_group *vg,
931 : : struct metadata_area *mda)
932 : : {
933 : 0 : struct text_context *tc = (struct text_context *) mda->metadata_locn;
934 : : char *slash;
935 : : char new_name[PATH_MAX];
936 : : size_t len;
937 : :
938 [ # # ]: 0 : if (!_vg_commit_file_backup(fid, vg, mda))
939 : 0 : return 0;
940 : :
941 : : /* vgrename? */
942 [ # # ]: 0 : if ((slash = strrchr(tc->path_live, '/')))
943 : 0 : slash = slash + 1;
944 : : else
945 : 0 : slash = tc->path_live;
946 : :
947 [ # # ]: 0 : if (strcmp(slash, vg->name)) {
948 : 0 : len = slash - tc->path_live;
949 : 0 : strncpy(new_name, tc->path_live, len);
950 : 0 : strcpy(new_name + len, vg->name);
951 : 0 : log_debug("Renaming %s to %s", tc->path_live, new_name);
952 [ # # ]: 0 : if (test_mode())
953 : 0 : log_verbose("Test mode: Skipping rename");
954 : : else {
955 [ # # ]: 0 : if (rename(tc->path_live, new_name)) {
956 : 0 : log_error("%s: rename to %s failed: %s",
957 : : tc->path_live, new_name,
958 : : strerror(errno));
959 : 0 : sync_dir(new_name);
960 : 0 : return 0;
961 : : }
962 : : }
963 : : }
964 : :
965 : 0 : return 1;
966 : : }
967 : :
968 : 0 : static int _vg_remove_file(struct format_instance *fid __attribute((unused)),
969 : : struct volume_group *vg __attribute((unused)),
970 : : struct metadata_area *mda)
971 : : {
972 : 0 : struct text_context *tc = (struct text_context *) mda->metadata_locn;
973 : :
974 [ # # ][ # # ]: 0 : if (path_exists(tc->path_edit) && unlink(tc->path_edit)) {
975 : 0 : log_sys_error("unlink", tc->path_edit);
976 : 0 : return 0;
977 : : }
978 : :
979 [ # # ][ # # ]: 0 : if (path_exists(tc->path_live) && unlink(tc->path_live)) {
980 : 0 : log_sys_error("unlink", tc->path_live);
981 : 0 : return 0;
982 : : }
983 : :
984 : 0 : sync_dir(tc->path_live);
985 : :
986 : 0 : return 1;
987 : : }
988 : :
989 : 1 : static int _scan_file(const struct format_type *fmt)
990 : : {
991 : : struct dirent *dirent;
992 : : struct dir_list *dl;
993 : : struct dm_list *dir_list;
994 : : char *tmp;
995 : : DIR *d;
996 : : struct volume_group *vg;
997 : : struct format_instance *fid;
998 : : char path[PATH_MAX];
999 : : char *vgname;
1000 : :
1001 : 1 : dir_list = &((struct mda_lists *) fmt->private)->dirs;
1002 : :
1003 [ - + ]: 1 : dm_list_iterate_items(dl, dir_list) {
1004 [ # # ]: 0 : if (!(d = opendir(dl->dir))) {
1005 : 0 : log_sys_error("opendir", dl->dir);
1006 : 0 : continue;
1007 : : }
1008 [ # # ]: 0 : while ((dirent = readdir(d)))
1009 [ # # ][ # # ]: 0 : if (strcmp(dirent->d_name, ".") &&
[ # # ][ # # ]
1010 : 0 : strcmp(dirent->d_name, "..") &&
1011 : 0 : (!(tmp = strstr(dirent->d_name, ".tmp")) ||
1012 : : tmp != dirent->d_name + strlen(dirent->d_name)
1013 : 0 : - 4)) {
1014 : 0 : vgname = dirent->d_name;
1015 [ # # ]: 0 : if (dm_snprintf(path, PATH_MAX, "%s/%s",
1016 : : dl->dir, vgname) < 0) {
1017 : 0 : log_error("Name too long %s/%s",
1018 : : dl->dir, vgname);
1019 : 0 : break;
1020 : : }
1021 : :
1022 : : /* FIXME stat file to see if it's changed */
1023 : 0 : fid = _text_create_text_instance(fmt, NULL, NULL,
1024 : : NULL);
1025 [ # # ]: 0 : if ((vg = _vg_read_file_name(fid, vgname,
1026 : : path)))
1027 : : /* FIXME Store creation host in vg */
1028 : 0 : lvmcache_update_vg(vg, 0);
1029 : : }
1030 : :
1031 [ # # ]: 0 : if (closedir(d))
1032 : 0 : log_sys_error("closedir", dl->dir);
1033 : : }
1034 : :
1035 : 1 : return 1;
1036 : : }
1037 : :
1038 : 0 : const char *vgname_from_mda(const struct format_type *fmt,
1039 : : struct device_area *dev_area, struct id *vgid,
1040 : : uint64_t *vgstatus, char **creation_host,
1041 : : uint64_t *mda_free_sectors)
1042 : : {
1043 : : struct raw_locn *rlocn;
1044 : : struct mda_header *mdah;
1045 : 0 : uint32_t wrap = 0;
1046 : 0 : const char *vgname = NULL;
1047 : 0 : unsigned int len = 0;
1048 : : char buf[NAME_LEN + 1] __attribute((aligned(8)));
1049 : : char uuid[64] __attribute((aligned(8)));
1050 : : uint64_t buffer_size, current_usage;
1051 : :
1052 [ # # ]: 0 : if (mda_free_sectors)
1053 : 0 : *mda_free_sectors = ((dev_area->size - MDA_HEADER_SIZE) / 2) >> SECTOR_SHIFT;
1054 : :
1055 [ # # ]: 0 : if (!dev_open(dev_area->dev))
1056 : 0 : return_NULL;
1057 : :
1058 [ # # ]: 0 : if (!(mdah = _raw_read_mda_header(fmt, dev_area)))
1059 : 0 : goto_out;
1060 : :
1061 : : /* FIXME Cope with returning a list */
1062 : 0 : rlocn = mdah->raw_locns;
1063 : :
1064 : : /*
1065 : : * If no valid offset, do not try to search for vgname
1066 : : */
1067 [ # # ]: 0 : if (!rlocn->offset)
1068 : 0 : goto out;
1069 : :
1070 : : /* Do quick check for a vgname */
1071 [ # # ]: 0 : if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
1072 : : NAME_LEN, buf))
1073 : 0 : goto_out;
1074 : :
1075 [ # # ][ # # ]: 0 : while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
[ # # ][ # # ]
1076 : : len < (NAME_LEN - 1))
1077 : 0 : len++;
1078 : :
1079 : 0 : buf[len] = '\0';
1080 : :
1081 : : /* Ignore this entry if the characters aren't permissible */
1082 [ # # ]: 0 : if (!validate_name(buf))
1083 : 0 : goto_out;
1084 : :
1085 : : /* We found a VG - now check the metadata */
1086 [ # # ]: 0 : if (rlocn->offset + rlocn->size > mdah->size)
1087 : 0 : wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size);
1088 : :
1089 [ # # ]: 0 : if (wrap > rlocn->offset) {
1090 : 0 : log_error("%s: metadata too large for circular buffer",
1091 : : dev_name(dev_area->dev));
1092 : 0 : goto out;
1093 : : }
1094 : :
1095 : : /* FIXME 64-bit */
1096 [ # # ]: 0 : if (!(vgname = text_vgname_import(fmt, dev_area->dev,
1097 : 0 : (off_t) (dev_area->start +
1098 : : rlocn->offset),
1099 : : (uint32_t) (rlocn->size - wrap),
1100 : 0 : (off_t) (dev_area->start +
1101 : : MDA_HEADER_SIZE),
1102 : : wrap, calc_crc, rlocn->checksum,
1103 : : vgid, vgstatus, creation_host)))
1104 : 0 : goto_out;
1105 : :
1106 : : /* Ignore this entry if the characters aren't permissible */
1107 [ # # ]: 0 : if (!validate_name(vgname)) {
1108 : 0 : vgname = NULL;
1109 : 0 : goto_out;
1110 : : }
1111 : :
1112 [ # # ]: 0 : if (!id_write_format(vgid, uuid, sizeof(uuid))) {
1113 : 0 : vgname = NULL;
1114 : 0 : goto_out;
1115 : : }
1116 : :
1117 : 0 : log_debug("%s: Found metadata at %" PRIu64 " size %" PRIu64
1118 : : " (in area at %" PRIu64 " size %" PRIu64
1119 : : ") for %s (%s)",
1120 : : dev_name(dev_area->dev), dev_area->start + rlocn->offset,
1121 : : rlocn->size, dev_area->start, dev_area->size, vgname, uuid);
1122 : :
1123 [ # # ]: 0 : if (mda_free_sectors) {
1124 : 0 : current_usage = (rlocn->size + SECTOR_SIZE - UINT64_C(1)) -
1125 : : (rlocn->size + SECTOR_SIZE - UINT64_C(1)) % SECTOR_SIZE;
1126 : 0 : buffer_size = mdah->size - MDA_HEADER_SIZE;
1127 : :
1128 [ # # ]: 0 : if (current_usage * 2 >= buffer_size)
1129 : 0 : *mda_free_sectors = UINT64_C(0);
1130 : : else
1131 : 0 : *mda_free_sectors = ((buffer_size - 2 * current_usage) / 2) >> SECTOR_SHIFT;
1132 : : }
1133 : :
1134 : : out:
1135 [ # # ]: 0 : if (!dev_close(dev_area->dev))
1136 : 0 : stack;
1137 : :
1138 : 0 : return vgname;
1139 : : }
1140 : :
1141 : 1 : static int _scan_raw(const struct format_type *fmt)
1142 : : {
1143 : : struct raw_list *rl;
1144 : : struct dm_list *raw_list;
1145 : : const char *vgname;
1146 : : struct volume_group *vg;
1147 : : struct format_instance fid;
1148 : : struct id vgid;
1149 : : uint64_t vgstatus;
1150 : :
1151 : 1 : raw_list = &((struct mda_lists *) fmt->private)->raws;
1152 : :
1153 : 1 : fid.fmt = fmt;
1154 : 1 : dm_list_init(&fid.metadata_areas);
1155 : :
1156 [ - + ]: 1 : dm_list_iterate_items(rl, raw_list) {
1157 : : /* FIXME We're reading mdah twice here... */
1158 [ # # ]: 0 : if ((vgname = vgname_from_mda(fmt, &rl->dev_area, &vgid, &vgstatus,
1159 : : NULL, NULL))) {
1160 [ # # ]: 0 : if ((vg = _vg_read_raw_area(&fid, vgname,
1161 : : &rl->dev_area, 0)))
1162 : 0 : lvmcache_update_vg(vg, 0);
1163 : : }
1164 : : }
1165 : :
1166 : 1 : return 1;
1167 : : }
1168 : :
1169 : 1 : static int _text_scan(const struct format_type *fmt)
1170 : : {
1171 : 1 : return (_scan_file(fmt) & _scan_raw(fmt));
1172 : : }
1173 : :
1174 : : /* For orphan, creates new mdas according to policy.
1175 : : Always have an mda between end-of-label and pe_align() boundary */
1176 : 0 : static int _mda_setup(const struct format_type *fmt,
1177 : : uint64_t pe_start, uint64_t pe_end,
1178 : : int pvmetadatacopies,
1179 : : uint64_t pvmetadatasize, struct dm_list *mdas,
1180 : : struct physical_volume *pv,
1181 : : struct volume_group *vg __attribute((unused)))
1182 : : {
1183 : : uint64_t mda_adjustment, disk_size, alignment, alignment_offset;
1184 : : uint64_t start1, mda_size1; /* First area - start of disk */
1185 : : uint64_t start2, mda_size2; /* Second area - end of disk */
1186 : 0 : uint64_t wipe_size = 8 << SECTOR_SHIFT;
1187 : 0 : size_t pagesize = lvm_getpagesize();
1188 : :
1189 [ # # ]: 0 : if (!pvmetadatacopies)
1190 : 0 : return 1;
1191 : :
1192 : 0 : alignment = pv->pe_align << SECTOR_SHIFT;
1193 : 0 : alignment_offset = pv->pe_align_offset << SECTOR_SHIFT;
1194 : 0 : disk_size = pv->size << SECTOR_SHIFT;
1195 : 0 : pe_start <<= SECTOR_SHIFT;
1196 : 0 : pe_end <<= SECTOR_SHIFT;
1197 : :
1198 [ # # ]: 0 : if (pe_end > disk_size) {
1199 : 0 : log_error("Physical extents end beyond end of device %s!",
1200 : : pv_dev_name(pv));
1201 : 0 : return 0;
1202 : : }
1203 : :
1204 : : /* Requested metadatasize */
1205 : 0 : mda_size1 = pvmetadatasize << SECTOR_SHIFT;
1206 : :
1207 : : /* Place mda straight after label area at start of disk */
1208 : 0 : start1 = LABEL_SCAN_SIZE;
1209 : :
1210 : : /* Unless the space available is tiny, round to PAGE_SIZE boundary */
1211 [ # # ][ # # ]: 0 : if ((!pe_start && !pe_end) ||
[ # # # # ]
1212 : 0 : ((pe_start > start1) && (pe_start - start1 >= MDA_SIZE_MIN))) {
1213 : 0 : mda_adjustment = start1 % pagesize;
1214 [ # # ]: 0 : if (mda_adjustment)
1215 : 0 : start1 += (pagesize - mda_adjustment);
1216 : : }
1217 : :
1218 : : /* Round up to pe_align boundary */
1219 : 0 : mda_adjustment = (mda_size1 + start1) % alignment;
1220 [ # # ]: 0 : if (mda_adjustment) {
1221 : 0 : mda_size1 += (alignment - mda_adjustment);
1222 : : /* Revert if it's now too large */
1223 [ # # ]: 0 : if (start1 + mda_size1 > disk_size)
1224 : 0 : mda_size1 -= (alignment - mda_adjustment);
1225 : : }
1226 : :
1227 : : /* Add pe_align_offset if on pe_align boundary */
1228 [ # # ][ # # ]: 0 : if (alignment_offset &&
1229 : 0 : (((start1 + mda_size1) % alignment) == 0)) {
1230 : 0 : mda_size1 += alignment_offset;
1231 : : /* Revert if it's now too large */
1232 [ # # ]: 0 : if (start1 + mda_size1 > disk_size)
1233 : 0 : mda_size1 -= alignment_offset;
1234 : : }
1235 : :
1236 : : /* Ensure it's not going to be bigger than the disk! */
1237 [ # # ]: 0 : if (start1 + mda_size1 > disk_size) {
1238 : 0 : log_warn("WARNING: metadata area fills disk leaving no "
1239 : : "space for data on %s.", pv_dev_name(pv));
1240 : : /* Leave some free space for rounding */
1241 : : /* Avoid empty data area as could cause tools problems */
1242 : 0 : mda_size1 = disk_size - start1 - alignment * 2;
1243 [ # # ]: 0 : if (start1 + mda_size1 > disk_size) {
1244 : 0 : log_error("Insufficient space for first mda on %s",
1245 : : pv_dev_name(pv));
1246 : 0 : return 0;
1247 : : }
1248 : : /* Round up to pe_align boundary */
1249 : 0 : mda_adjustment = (mda_size1 + start1) % alignment;
1250 [ # # ]: 0 : if (mda_adjustment)
1251 : 0 : mda_size1 += (alignment - mda_adjustment);
1252 : : /* Only have 1 mda in this case */
1253 : 0 : pvmetadatacopies = 1;
1254 : : }
1255 : :
1256 : : /* If we already have PEs, avoid overlap */
1257 [ # # ][ # # ]: 0 : if (pe_start || pe_end) {
1258 [ # # ]: 0 : if (pe_start <= start1)
1259 : 0 : mda_size1 = 0;
1260 [ # # ]: 0 : else if (start1 + mda_size1 > pe_start)
1261 : 0 : mda_size1 = pe_start - start1;
1262 : : }
1263 : :
1264 : : /* FIXME If creating new mdas, wipe them! */
1265 [ # # ]: 0 : if (mda_size1) {
1266 [ # # ]: 0 : if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start1,
1267 : : mda_size1))
1268 : 0 : return 0;
1269 : :
1270 [ # # ][ # # ]: 0 : if (!dev_set((struct device *) pv->dev, start1,
1271 : 0 : (size_t) (mda_size1 >
1272 : 0 : wipe_size ? : mda_size1), 0)) {
1273 : 0 : log_error("Failed to wipe new metadata area");
1274 : 0 : return 0;
1275 : : }
1276 : :
1277 [ # # ]: 0 : if (pvmetadatacopies == 1)
1278 : 0 : return 1;
1279 : : } else
1280 : 0 : start1 = 0;
1281 : :
1282 : : /* A second copy at end of disk */
1283 : 0 : mda_size2 = pvmetadatasize << SECTOR_SHIFT;
1284 : :
1285 : : /* Ensure it's not going to be bigger than the disk! */
1286 [ # # ]: 0 : if (mda_size2 > disk_size)
1287 : 0 : mda_size2 = disk_size - start1 - mda_size1;
1288 : :
1289 : 0 : mda_adjustment = (disk_size - mda_size2) % alignment;
1290 [ # # ]: 0 : if (mda_adjustment)
1291 : 0 : mda_size2 += mda_adjustment;
1292 : :
1293 : 0 : start2 = disk_size - mda_size2;
1294 : :
1295 : : /* If we already have PEs, avoid overlap */
1296 [ # # ][ # # ]: 0 : if (pe_start || pe_end) {
1297 [ # # ]: 0 : if (start2 < pe_end) {
1298 : 0 : mda_size2 -= (pe_end - start2);
1299 : 0 : start2 = pe_end;
1300 : : }
1301 : : }
1302 : :
1303 : : /* If we already have a first mda, avoid overlap */
1304 [ # # ]: 0 : if (mda_size1) {
1305 [ # # ]: 0 : if (start2 < start1 + mda_size1) {
1306 : 0 : mda_size2 -= (start1 + mda_size1 - start2);
1307 : 0 : start2 = start1 + mda_size1;
1308 : : }
1309 : : /* No room for any PEs here now! */
1310 : : }
1311 : :
1312 [ # # ]: 0 : if (mda_size2) {
1313 [ # # ]: 0 : if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start2,
1314 : 0 : mda_size2)) return 0;
1315 [ # # ][ # # ]: 0 : if (!dev_set(pv->dev, start2,
1316 : 0 : (size_t) (mda_size1 >
1317 : 0 : wipe_size ? : mda_size1), 0)) {
1318 : 0 : log_error("Failed to wipe new metadata area");
1319 : 0 : return 0;
1320 : : }
1321 : : } else
1322 : 0 : return 0;
1323 : :
1324 : 0 : return 1;
1325 : : }
1326 : :
1327 : : /* Only for orphans */
1328 : : /* Set label_sector to -1 if rewriting existing label into same sector */
1329 : : /* If mdas is supplied it overwrites existing mdas e.g. used with pvcreate */
1330 : 0 : static int _text_pv_write(const struct format_type *fmt, struct physical_volume *pv,
1331 : : struct dm_list *mdas, int64_t label_sector)
1332 : : {
1333 : : struct label *label;
1334 : : struct lvmcache_info *info;
1335 : : struct mda_context *mdac;
1336 : : struct metadata_area *mda;
1337 : : char buf[MDA_HEADER_SIZE] __attribute((aligned(8)));
1338 : 0 : struct mda_header *mdah = (struct mda_header *) buf;
1339 : : uint64_t adjustment;
1340 : : struct data_area_list *da;
1341 : :
1342 : : /* FIXME Test mode don't update cache? */
1343 : :
1344 [ # # ]: 0 : if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev,
1345 : : FMT_TEXT_ORPHAN_VG_NAME, NULL, 0)))
1346 : 0 : return_0;
1347 : 0 : label = info->label;
1348 : :
1349 [ # # ]: 0 : if (label_sector != -1)
1350 : 0 : label->sector = label_sector;
1351 : :
1352 : 0 : info->device_size = pv->size << SECTOR_SHIFT;
1353 : 0 : info->fmt = fmt;
1354 : :
1355 : : /* If mdas supplied, use them regardless of existing ones, */
1356 : : /* otherwise retain existing ones */
1357 [ # # ]: 0 : if (mdas) {
1358 [ # # ]: 0 : if (info->mdas.n)
1359 : 0 : del_mdas(&info->mdas);
1360 : : else
1361 : 0 : dm_list_init(&info->mdas);
1362 [ # # ]: 0 : dm_list_iterate_items(mda, mdas) {
1363 : 0 : mdac = mda->metadata_locn;
1364 : 0 : log_debug("Creating metadata area on %s at sector %"
1365 : : PRIu64 " size %" PRIu64 " sectors",
1366 : : dev_name(mdac->area.dev),
1367 : : mdac->area.start >> SECTOR_SHIFT,
1368 : : mdac->area.size >> SECTOR_SHIFT);
1369 : 0 : add_mda(fmt, NULL, &info->mdas, mdac->area.dev,
1370 : : mdac->area.start, mdac->area.size);
1371 : : }
1372 : : /* FIXME Temporary until mda creation supported by tools */
1373 [ # # ]: 0 : } else if (!info->mdas.n) {
1374 : 0 : dm_list_init(&info->mdas);
1375 : : }
1376 : :
1377 : : /*
1378 : : * If no pe_start supplied but PV already exists,
1379 : : * get existing value; use-cases include:
1380 : : * - pvcreate on PV without prior pvremove
1381 : : * - vgremove on VG with PV(s) that have pe_start=0 (hacked cfg)
1382 : : */
1383 [ # # ]: 0 : if (info->das.n) {
1384 [ # # ]: 0 : if (!pv->pe_start)
1385 [ # # ]: 0 : dm_list_iterate_items(da, &info->das)
1386 : 0 : pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT;
1387 : 0 : del_das(&info->das);
1388 : : } else
1389 : 0 : dm_list_init(&info->das);
1390 : :
1391 : : #if 0
1392 : : /*
1393 : : * FIXME: ideally a pre-existing pe_start seen in .pv_write
1394 : : * would always be preserved BUT 'pvcreate on PV without prior pvremove'
1395 : : * could easily cause the pe_start to overlap with the first mda!
1396 : : */
1397 : : if (pv->pe_start) {
1398 : : log_very_verbose("%s: preserving pe_start=%lu",
1399 : : pv_dev_name(pv), pv->pe_start);
1400 : : goto preserve_pe_start;
1401 : : }
1402 : : #endif
1403 : :
1404 : : /*
1405 : : * If pe_start is still unset, set it to first aligned
1406 : : * sector after any metadata areas that begin before pe_start.
1407 : : */
1408 [ # # ]: 0 : if (!pv->pe_start) {
1409 : 0 : pv->pe_start = pv->pe_align;
1410 [ # # ]: 0 : if (pv->pe_align_offset)
1411 : 0 : pv->pe_start += pv->pe_align_offset;
1412 : : }
1413 [ # # ]: 0 : dm_list_iterate_items(mda, &info->mdas) {
1414 : 0 : mdac = (struct mda_context *) mda->metadata_locn;
1415 [ # # ][ # # : 0 : if (pv->dev == mdac->area.dev &&
# # # # ]
[ # # ]
1416 : 0 : ((mdac->area.start <= (pv->pe_start << SECTOR_SHIFT)) ||
1417 : 0 : (mdac->area.start <= lvm_getpagesize() &&
1418 : 0 : pv->pe_start < (lvm_getpagesize() >> SECTOR_SHIFT))) &&
1419 : 0 : (mdac->area.start + mdac->area.size >
1420 : 0 : (pv->pe_start << SECTOR_SHIFT))) {
1421 : 0 : pv->pe_start = (mdac->area.start + mdac->area.size)
1422 : : >> SECTOR_SHIFT;
1423 : : /* Adjust pe_start to: (N * pe_align) + pe_align_offset */
1424 [ # # ]: 0 : if (pv->pe_align) {
1425 : 0 : adjustment =
1426 : 0 : (pv->pe_start - pv->pe_align_offset) % pv->pe_align;
1427 [ # # ]: 0 : if (adjustment)
1428 : 0 : pv->pe_start += pv->pe_align - adjustment;
1429 : :
1430 [ # # ]: 0 : log_very_verbose("%s: setting pe_start=%" PRIu64
1431 : : " (orig_pe_start=%" PRIu64 ", "
1432 : : "pe_align=%lu, pe_align_offset=%lu, "
1433 : : "adjustment=%" PRIu64 ")",
1434 : : pv_dev_name(pv), pv->pe_start,
1435 : : (adjustment ?
1436 : : pv->pe_start -= pv->pe_align - adjustment :
1437 : : pv->pe_start),
1438 : : pv->pe_align, pv->pe_align_offset, adjustment);
1439 : : }
1440 : : }
1441 : : }
1442 [ # # ]: 0 : if (pv->pe_start >= pv->size) {
1443 : 0 : log_error("Data area is beyond end of device %s!",
1444 : : pv_dev_name(pv));
1445 : 0 : return 0;
1446 : : }
1447 : :
1448 : : /* FIXME: preserve_pe_start: */
1449 [ # # ]: 0 : if (!add_da
1450 : : (NULL, &info->das, pv->pe_start << SECTOR_SHIFT, UINT64_C(0)))
1451 : 0 : return_0;
1452 : :
1453 [ # # ]: 0 : if (!dev_open(pv->dev))
1454 : 0 : return_0;
1455 : :
1456 [ # # ]: 0 : dm_list_iterate_items(mda, &info->mdas) {
1457 : 0 : mdac = mda->metadata_locn;
1458 : 0 : memset(&buf, 0, sizeof(buf));
1459 : 0 : mdah->size = mdac->area.size;
1460 [ # # ]: 0 : if (!_raw_write_mda_header(fmt, mdac->area.dev,
1461 : : mdac->area.start, mdah)) {
1462 [ # # ]: 0 : if (!dev_close(pv->dev))
1463 : 0 : stack;
1464 : 0 : return_0;
1465 : : }
1466 : : }
1467 : :
1468 [ # # ]: 0 : if (!label_write(pv->dev, label)) {
1469 : 0 : dev_close(pv->dev);
1470 : 0 : return_0;
1471 : : }
1472 : :
1473 [ # # ]: 0 : if (!dev_close(pv->dev))
1474 : 0 : return_0;
1475 : :
1476 : 0 : return 1;
1477 : : }
1478 : :
1479 : 0 : static int _add_raw(struct dm_list *raw_list, struct device_area *dev_area)
1480 : : {
1481 : : struct raw_list *rl;
1482 : :
1483 : : /* Already present? */
1484 [ # # ]: 0 : dm_list_iterate_items(rl, raw_list) {
1485 : : /* FIXME Check size/overlap consistency too */
1486 [ # # ][ # # ]: 0 : if (rl->dev_area.dev == dev_area->dev &&
1487 : 0 : rl->dev_area.start == dev_area->start)
1488 : 0 : return 1;
1489 : : }
1490 : :
1491 [ # # ]: 0 : if (!(rl = dm_malloc(sizeof(struct raw_list)))) {
1492 : 0 : log_error("_add_raw allocation failed");
1493 : 0 : return 0;
1494 : : }
1495 : 0 : memcpy(&rl->dev_area, dev_area, sizeof(*dev_area));
1496 : 0 : dm_list_add(raw_list, &rl->list);
1497 : :
1498 : 0 : return 1;
1499 : : }
1500 : :
1501 : 0 : static int _get_pv_if_in_vg(struct lvmcache_info *info,
1502 : : struct physical_volume *pv)
1503 : : {
1504 [ # # ][ # # : 0 : if (info->vginfo && info->vginfo->vgname &&
# # # # ]
1505 : 0 : !is_orphan_vg(info->vginfo->vgname) &&
1506 : 0 : get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
1507 : 0 : info->vginfo->vgid, info->dev->pvid, pv))
1508 : 0 : return 1;
1509 : :
1510 : 0 : return 0;
1511 : : }
1512 : :
1513 : 0 : static int _populate_pv_fields(struct lvmcache_info *info,
1514 : : struct physical_volume *pv,
1515 : : int scan_label_only)
1516 : : {
1517 : : struct data_area_list *da;
1518 : :
1519 : : /* Have we already cached vgname? */
1520 [ # # ][ # # ]: 0 : if (!scan_label_only && _get_pv_if_in_vg(info, pv))
1521 : 0 : return 1;
1522 : :
1523 : : /* Perform full scan (just the first time) and try again */
1524 [ # # ][ # # ]: 0 : if (!scan_label_only && !memlock() && !full_scan_done()) {
[ # # ]
1525 : 0 : lvmcache_label_scan(info->fmt->cmd, 2);
1526 : :
1527 [ # # ]: 0 : if (_get_pv_if_in_vg(info, pv))
1528 : 0 : return 1;
1529 : : }
1530 : :
1531 : : /* Orphan */
1532 : 0 : pv->dev = info->dev;
1533 : 0 : pv->fmt = info->fmt;
1534 : 0 : pv->size = info->device_size >> SECTOR_SHIFT;
1535 : 0 : pv->vg_name = FMT_TEXT_ORPHAN_VG_NAME;
1536 : 0 : memcpy(&pv->id, &info->dev->pvid, sizeof(pv->id));
1537 : :
1538 : : /* Currently only support exactly one data area */
1539 [ # # ]: 0 : if (dm_list_size(&info->das) != 1) {
1540 : 0 : log_error("Must be exactly one data area (found %d) on PV %s",
1541 : : dm_list_size(&info->das), dev_name(info->dev));
1542 : 0 : return 0;
1543 : : }
1544 : :
1545 [ # # ]: 0 : dm_list_iterate_items(da, &info->das)
1546 : 0 : pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT;
1547 : :
1548 : 0 : return 1;
1549 : : }
1550 : :
1551 : : /*
1552 : : * Copy constructor for a metadata_area.
1553 : : */
1554 : 0 : static struct metadata_area *_mda_copy(struct dm_pool *mem,
1555 : : struct metadata_area *mda)
1556 : : {
1557 : : struct metadata_area *mda_new;
1558 : : struct mda_context *mdac, *mdac_new;
1559 : :
1560 [ # # ]: 0 : if (!(mda_new = dm_pool_alloc(mem, sizeof(*mda_new)))) {
1561 : 0 : log_error("metadata_area allocation failed");
1562 : 0 : return NULL;
1563 : : }
1564 : : /* FIXME: Should have a per-format constructor here */
1565 : 0 : mdac = (struct mda_context *) mda->metadata_locn;
1566 [ # # ]: 0 : if (!(mdac_new = dm_pool_alloc(mem, sizeof(*mdac_new)))) {
1567 : 0 : log_error("mda_context allocation failed");
1568 : 0 : dm_pool_free(mem, mda_new);
1569 : 0 : return NULL;
1570 : : }
1571 : 0 : memcpy(mda_new, mda, sizeof(*mda));
1572 : 0 : memcpy(mdac_new, mdac, sizeof(*mdac));
1573 : 0 : mda_new->metadata_locn = mdac_new;
1574 : :
1575 : : /* FIXME mda 'list' left invalid here */
1576 : :
1577 : 0 : return mda_new;
1578 : : }
1579 : :
1580 : :
1581 : 0 : static int _text_pv_read(const struct format_type *fmt, const char *pv_name,
1582 : : struct physical_volume *pv, struct dm_list *mdas,
1583 : : int scan_label_only)
1584 : : {
1585 : : struct metadata_area *mda, *mda_new;
1586 : : struct label *label;
1587 : : struct device *dev;
1588 : : struct lvmcache_info *info;
1589 : :
1590 [ # # ]: 0 : if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter)))
1591 : 0 : return_0;
1592 : :
1593 [ # # ]: 0 : if (!(label_read(dev, &label, UINT64_C(0))))
1594 : 0 : return_0;
1595 : 0 : info = (struct lvmcache_info *) label->info;
1596 : :
1597 [ # # ]: 0 : if (!_populate_pv_fields(info, pv, scan_label_only))
1598 : 0 : return 0;
1599 : :
1600 [ # # ]: 0 : if (!mdas)
1601 : 0 : return 1;
1602 : :
1603 : : /* Add copy of mdas to supplied list */
1604 [ # # ]: 0 : dm_list_iterate_items(mda, &info->mdas) {
1605 : 0 : mda_new = _mda_copy(fmt->cmd->mem, mda);
1606 [ # # ]: 0 : if (!mda_new)
1607 : 0 : return 0;
1608 : 0 : dm_list_add(mdas, &mda_new->list);
1609 : : }
1610 : :
1611 : 0 : return 1;
1612 : : }
1613 : :
1614 : 0 : static void _text_destroy_instance(struct format_instance *fid __attribute((unused)))
1615 : : {
1616 : 0 : }
1617 : :
1618 : 3 : static void _free_dirs(struct dm_list *dir_list)
1619 : : {
1620 : : struct dm_list *dl, *tmp;
1621 : :
1622 [ - + ]: 3 : dm_list_iterate_safe(dl, tmp, dir_list) {
1623 : 0 : dm_list_del(dl);
1624 : 0 : dm_free(dl);
1625 : : }
1626 : 3 : }
1627 : :
1628 : 3 : static void _free_raws(struct dm_list *raw_list)
1629 : : {
1630 : : struct dm_list *rl, *tmp;
1631 : :
1632 [ - + ]: 3 : dm_list_iterate_safe(rl, tmp, raw_list) {
1633 : 0 : dm_list_del(rl);
1634 : 0 : dm_free(rl);
1635 : : }
1636 : 3 : }
1637 : :
1638 : 3 : static void _text_destroy(const struct format_type *fmt)
1639 : : {
1640 [ + - ]: 3 : if (fmt->private) {
1641 : 3 : _free_dirs(&((struct mda_lists *) fmt->private)->dirs);
1642 : 3 : _free_raws(&((struct mda_lists *) fmt->private)->raws);
1643 : 3 : dm_free(fmt->private);
1644 : : }
1645 : :
1646 : 3 : dm_free((void *)fmt);
1647 : 3 : }
1648 : :
1649 : : static struct metadata_area_ops _metadata_text_file_ops = {
1650 : : .vg_read = _vg_read_file,
1651 : : .vg_read_precommit = _vg_read_precommit_file,
1652 : : .vg_write = _vg_write_file,
1653 : : .vg_remove = _vg_remove_file,
1654 : : .vg_commit = _vg_commit_file
1655 : : };
1656 : :
1657 : : static struct metadata_area_ops _metadata_text_file_backup_ops = {
1658 : : .vg_read = _vg_read_file,
1659 : : .vg_write = _vg_write_file,
1660 : : .vg_remove = _vg_remove_file,
1661 : : .vg_commit = _vg_commit_file_backup
1662 : : };
1663 : :
1664 : : static struct metadata_area_ops _metadata_text_raw_ops = {
1665 : : .vg_read = _vg_read_raw,
1666 : : .vg_read_precommit = _vg_read_precommit_raw,
1667 : : .vg_write = _vg_write_raw,
1668 : : .vg_remove = _vg_remove_raw,
1669 : : .vg_precommit = _vg_precommit_raw,
1670 : : .vg_commit = _vg_commit_raw,
1671 : : .vg_revert = _vg_revert_raw,
1672 : : .mda_free_sectors = _mda_free_sectors_raw,
1673 : : .mda_total_sectors = _mda_total_sectors_raw,
1674 : : .mda_in_vg = _mda_in_vg_raw,
1675 : : .pv_analyze_mda = _pv_analyze_mda_raw,
1676 : : };
1677 : :
1678 : : /* pvmetadatasize in sectors */
1679 : : /*
1680 : : * pe_start goal: FIXME -- reality of .pv_write complexity undermines this goal
1681 : : * - In cases where a pre-existing pe_start is provided (pvcreate --restorefile
1682 : : * and vgconvert): pe_start must not be changed (so pv->pe_start = pe_start).
1683 : : * - In cases where pe_start is 0: leave pv->pe_start as 0 and defer the
1684 : : * setting of pv->pe_start to .pv_write
1685 : : */
1686 : 0 : static int _text_pv_setup(const struct format_type *fmt,
1687 : : uint64_t pe_start, uint32_t extent_count,
1688 : : uint32_t extent_size, unsigned long data_alignment,
1689 : : unsigned long data_alignment_offset,
1690 : : int pvmetadatacopies,
1691 : : uint64_t pvmetadatasize, struct dm_list *mdas,
1692 : : struct physical_volume *pv, struct volume_group *vg)
1693 : : {
1694 : : struct metadata_area *mda, *mda_new, *mda2;
1695 : : struct mda_context *mdac, *mdac2;
1696 : : struct dm_list *pvmdas;
1697 : : struct lvmcache_info *info;
1698 : : int found;
1699 : 0 : uint64_t pe_end = 0;
1700 : 0 : unsigned mda_count = 0;
1701 : 0 : uint64_t mda_size2 = 0;
1702 : : uint64_t pe_count;
1703 : :
1704 : : /* FIXME Cope with pvchange */
1705 : : /* FIXME Merge code with _text_create_text_instance */
1706 : :
1707 : : /* If new vg, add any further mdas on this PV to the fid's mda list */
1708 [ # # ]: 0 : if (vg) {
1709 : : /* Iterate through all mdas on this PV */
1710 [ # # ]: 0 : if ((info = info_from_pvid(pv->dev->pvid, 0))) {
1711 : 0 : pvmdas = &info->mdas;
1712 [ # # ]: 0 : dm_list_iterate_items(mda, pvmdas) {
1713 : 0 : mda_count++;
1714 : 0 : mdac =
1715 : 0 : (struct mda_context *) mda->metadata_locn;
1716 : :
1717 : : /* FIXME Check it isn't already in use */
1718 : :
1719 : : /* Reduce usable device size */
1720 [ # # ]: 0 : if (mda_count > 1)
1721 : 0 : mda_size2 = mdac->area.size >> SECTOR_SHIFT;
1722 : :
1723 : : /* Ensure it isn't already on list */
1724 : 0 : found = 0;
1725 [ # # ]: 0 : dm_list_iterate_items(mda2, mdas) {
1726 [ # # ]: 0 : if (mda2->ops !=
1727 : 0 : &_metadata_text_raw_ops) continue;
1728 : 0 : mdac2 =
1729 : 0 : (struct mda_context *)
1730 : : mda2->metadata_locn;
1731 [ # # ]: 0 : if (!memcmp
1732 : 0 : (&mdac2->area, &mdac->area,
1733 : : sizeof(mdac->area))) {
1734 : 0 : found = 1;
1735 : 0 : break;
1736 : : }
1737 : : }
1738 [ # # ]: 0 : if (found)
1739 : 0 : continue;
1740 : :
1741 : 0 : mda_new = _mda_copy(fmt->cmd->mem, mda);
1742 [ # # ]: 0 : if (!mda_new)
1743 : 0 : return_0;
1744 : 0 : dm_list_add(mdas, &mda_new->list);
1745 : : /* FIXME multiple dev_areas inside area */
1746 : : }
1747 : : }
1748 : :
1749 : : /* FIXME Cope with genuine pe_count 0 */
1750 : :
1751 : : /* If missing, estimate pv->size from file-based metadata */
1752 [ # # ][ # # ]: 0 : if (!pv->size && pv->pe_count)
1753 : 0 : pv->size = pv->pe_count * (uint64_t) vg->extent_size +
1754 : 0 : pv->pe_start + mda_size2;
1755 : :
1756 : : /* Recalculate number of extents that will fit */
1757 [ # # ]: 0 : if (!pv->pe_count) {
1758 : 0 : pe_count = (pv->size - pv->pe_start - mda_size2) /
1759 : : vg->extent_size;
1760 [ # # ]: 0 : if (pe_count > UINT32_MAX) {
1761 : 0 : log_error("PV %s too large for extent size %s.",
1762 : : pv_dev_name(pv),
1763 : : display_size(vg->cmd, (uint64_t) vg->extent_size));
1764 : 0 : return 0;
1765 : : }
1766 : 0 : pv->pe_count = (uint32_t) pe_count;
1767 : : }
1768 : :
1769 : : /* Unlike LVM1, we don't store this outside a VG */
1770 : : /* FIXME Default from config file? vgextend cmdline flag? */
1771 : 0 : pv->status |= ALLOCATABLE_PV;
1772 : : } else {
1773 [ # # ]: 0 : if (pe_start)
1774 : 0 : pv->pe_start = pe_start;
1775 : :
1776 [ # # ]: 0 : if (!data_alignment)
1777 : 0 : data_alignment = find_config_tree_int(pv->fmt->cmd,
1778 : : "devices/data_alignment",
1779 : : 0) * 2;
1780 : :
1781 [ # # ][ # # ]: 0 : if (set_pe_align(pv, data_alignment) != data_alignment &&
1782 : : data_alignment)
1783 : 0 : log_warn("WARNING: %s: Overriding data alignment to "
1784 : : "%lu sectors (requested %lu sectors)",
1785 : : pv_dev_name(pv), pv->pe_align, data_alignment);
1786 : :
1787 [ # # ][ # # ]: 0 : if (set_pe_align_offset(pv, data_alignment_offset) != data_alignment_offset &&
1788 : : data_alignment_offset)
1789 : 0 : log_warn("WARNING: %s: Overriding data alignment offset to "
1790 : : "%lu sectors (requested %lu sectors)",
1791 : : pv_dev_name(pv), pv->pe_align_offset, data_alignment_offset);
1792 : :
1793 [ # # ]: 0 : if (pv->pe_align < pv->pe_align_offset) {
1794 : 0 : log_error("%s: pe_align (%lu sectors) must not be less "
1795 : : "than pe_align_offset (%lu sectors)",
1796 : : pv_dev_name(pv), pv->pe_align, pv->pe_align_offset);
1797 : 0 : return 0;
1798 : : }
1799 : :
1800 : : /*
1801 : : * This initialization has a side-effect of allowing
1802 : : * orphaned PVs to be created with the proper alignment.
1803 : : * Setting pv->pe_start here circumvents .pv_write's
1804 : : * "pvcreate on PV without prior pvremove" retreival of
1805 : : * the PV's previous pe_start.
1806 : : * - Without this you get actual != expected pe_start
1807 : : * failures in the testsuite.
1808 : : */
1809 [ # # ][ # # ]: 0 : if (!pe_start && pv->pe_start < pv->pe_align)
1810 : 0 : pv->pe_start = pv->pe_align;
1811 : :
1812 [ # # ]: 0 : if (extent_count)
1813 : 0 : pe_end = pe_start + extent_count * extent_size - 1;
1814 [ # # ]: 0 : if (!_mda_setup(fmt, pe_start, pe_end, pvmetadatacopies,
1815 : : pvmetadatasize, mdas, pv, vg))
1816 : 0 : return_0;
1817 : : }
1818 : :
1819 : 0 : return 1;
1820 : : }
1821 : :
1822 : : /* NULL vgname means use only the supplied context e.g. an archive file */
1823 : 1 : static struct format_instance *_text_create_text_instance(const struct format_type
1824 : : *fmt, const char *vgname,
1825 : : const char *vgid,
1826 : : void *context)
1827 : : {
1828 : : struct format_instance *fid;
1829 : : struct text_fid_context *fidtc;
1830 : : struct metadata_area *mda, *mda_new;
1831 : : struct mda_context *mdac;
1832 : : struct dir_list *dl;
1833 : : struct raw_list *rl;
1834 : : struct dm_list *dir_list, *raw_list, *mdas;
1835 : : char path[PATH_MAX];
1836 : : struct lvmcache_vginfo *vginfo;
1837 : : struct lvmcache_info *info;
1838 : :
1839 [ - + ]: 1 : if (!(fid = dm_pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
1840 : 0 : log_error("Couldn't allocate format instance object.");
1841 : 0 : return NULL;
1842 : : }
1843 : :
1844 [ - + ]: 1 : if (!(fidtc = (struct text_fid_context *)
1845 : 1 : dm_pool_zalloc(fmt->cmd->mem,sizeof(*fidtc)))) {
1846 : 0 : log_error("Couldn't allocate text_fid_context.");
1847 : 0 : return NULL;
1848 : : }
1849 : :
1850 : 1 : fidtc->raw_metadata_buf = NULL;
1851 : 1 : fid->private = (void *) fidtc;
1852 : :
1853 : 1 : fid->fmt = fmt;
1854 : 1 : dm_list_init(&fid->metadata_areas);
1855 : :
1856 [ - + ]: 1 : if (!vgname) {
1857 [ # # ]: 0 : if (!(mda = dm_pool_alloc(fmt->cmd->mem, sizeof(*mda))))
1858 : 0 : return_NULL;
1859 : 0 : mda->ops = &_metadata_text_file_backup_ops;
1860 : 0 : mda->metadata_locn = context;
1861 : 0 : dm_list_add(&fid->metadata_areas, &mda->list);
1862 : : } else {
1863 : 1 : dir_list = &((struct mda_lists *) fmt->private)->dirs;
1864 : :
1865 [ - + ]: 1 : dm_list_iterate_items(dl, dir_list) {
1866 [ # # ]: 0 : if (dm_snprintf(path, PATH_MAX, "%s/%s",
1867 : : dl->dir, vgname) < 0) {
1868 : 0 : log_error("Name too long %s/%s", dl->dir,
1869 : : vgname);
1870 : 0 : return NULL;
1871 : : }
1872 : :
1873 : 0 : context = create_text_context(fmt->cmd, path, NULL);
1874 [ # # ]: 0 : if (!(mda = dm_pool_alloc(fmt->cmd->mem, sizeof(*mda))))
1875 : 0 : return_NULL;
1876 : 0 : mda->ops = &_metadata_text_file_ops;
1877 : 0 : mda->metadata_locn = context;
1878 : 0 : dm_list_add(&fid->metadata_areas, &mda->list);
1879 : : }
1880 : :
1881 : 1 : raw_list = &((struct mda_lists *) fmt->private)->raws;
1882 : :
1883 [ - + ]: 1 : dm_list_iterate_items(rl, raw_list) {
1884 : : /* FIXME Cache this; rescan below if some missing */
1885 [ # # ]: 0 : if (!_raw_holds_vgname(fid, &rl->dev_area, vgname))
1886 : 0 : continue;
1887 : :
1888 [ # # ]: 0 : if (!(mda = dm_pool_alloc(fmt->cmd->mem, sizeof(*mda))))
1889 : 0 : return_NULL;
1890 : :
1891 [ # # ]: 0 : if (!(mdac = dm_pool_alloc(fmt->cmd->mem, sizeof(*mdac))))
1892 : 0 : return_NULL;
1893 : 0 : mda->metadata_locn = mdac;
1894 : : /* FIXME Allow multiple dev_areas inside area */
1895 : 0 : memcpy(&mdac->area, &rl->dev_area, sizeof(mdac->area));
1896 : 0 : mda->ops = &_metadata_text_raw_ops;
1897 : : /* FIXME MISTAKE? mda->metadata_locn = context; */
1898 : 0 : dm_list_add(&fid->metadata_areas, &mda->list);
1899 : : }
1900 : :
1901 : : /* Scan PVs in VG for any further MDAs */
1902 : 1 : lvmcache_label_scan(fmt->cmd, 0);
1903 [ - + ]: 1 : if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
1904 : 0 : goto_out;
1905 [ - + ]: 1 : dm_list_iterate_items(info, &vginfo->infos) {
1906 : 0 : mdas = &info->mdas;
1907 [ # # ]: 0 : dm_list_iterate_items(mda, mdas) {
1908 : : /* FIXME Check it holds this VG */
1909 : 0 : mda_new = _mda_copy(fmt->cmd->mem, mda);
1910 [ # # ]: 0 : if (!mda_new)
1911 : 0 : return_NULL;
1912 : 0 : dm_list_add(&fid->metadata_areas, &mda_new->list);
1913 : : }
1914 : : }
1915 : : /* FIXME Check raw metadata area count - rescan if required */
1916 : : }
1917 : :
1918 : : out:
1919 : 1 : return fid;
1920 : : }
1921 : :
1922 : 0 : void *create_text_context(struct cmd_context *cmd, const char *path,
1923 : : const char *desc)
1924 : : {
1925 : : struct text_context *tc;
1926 : : char *tmp;
1927 : :
1928 [ # # ][ # # ]: 0 : if ((tmp = strstr(path, ".tmp")) && (tmp == path + strlen(path) - 4)) {
1929 : 0 : log_error("%s: Volume group filename may not end in .tmp",
1930 : : path);
1931 : 0 : return NULL;
1932 : : }
1933 : :
1934 [ # # ]: 0 : if (!(tc = dm_pool_alloc(cmd->mem, sizeof(*tc))))
1935 : 0 : return_NULL;
1936 : :
1937 [ # # ]: 0 : if (!(tc->path_live = dm_pool_strdup(cmd->mem, path)))
1938 : 0 : goto_bad;
1939 : :
1940 [ # # ]: 0 : if (!(tc->path_edit = dm_pool_alloc(cmd->mem, strlen(path) + 5)))
1941 : 0 : goto_bad;
1942 : :
1943 : 0 : sprintf(tc->path_edit, "%s.tmp", path);
1944 : :
1945 [ # # ]: 0 : if (!desc)
1946 : 0 : desc = "";
1947 : :
1948 [ # # ]: 0 : if (!(tc->desc = dm_pool_strdup(cmd->mem, desc)))
1949 : 0 : goto_bad;
1950 : :
1951 : 0 : return (void *) tc;
1952 : :
1953 : : bad:
1954 : 0 : dm_pool_free(cmd->mem, tc);
1955 : :
1956 : 0 : log_error("Couldn't allocate text format context object.");
1957 : 0 : return NULL;
1958 : : }
1959 : :
1960 : : static struct format_handler _text_handler = {
1961 : : .scan = _text_scan,
1962 : : .pv_read = _text_pv_read,
1963 : : .pv_setup = _text_pv_setup,
1964 : : .pv_write = _text_pv_write,
1965 : : .vg_setup = _text_vg_setup,
1966 : : .lv_setup = _text_lv_setup,
1967 : : .create_instance = _text_create_text_instance,
1968 : : .destroy_instance = _text_destroy_instance,
1969 : : .destroy = _text_destroy
1970 : : };
1971 : :
1972 : 0 : static int _add_dir(const char *dir, struct dm_list *dir_list)
1973 : : {
1974 : : struct dir_list *dl;
1975 : :
1976 [ # # ]: 0 : if (dm_create_dir(dir)) {
1977 [ # # ]: 0 : if (!(dl = dm_malloc(sizeof(struct dm_list) + strlen(dir) + 1))) {
1978 : 0 : log_error("_add_dir allocation failed");
1979 : 0 : return 0;
1980 : : }
1981 : 0 : log_very_verbose("Adding text format metadata dir: %s", dir);
1982 : 0 : strcpy(dl->dir, dir);
1983 : 0 : dm_list_add(dir_list, &dl->list);
1984 : 0 : return 1;
1985 : : }
1986 : :
1987 : 0 : return 0;
1988 : : }
1989 : :
1990 : 0 : static int _get_config_disk_area(struct cmd_context *cmd,
1991 : : struct config_node *cn, struct dm_list *raw_list)
1992 : : {
1993 : : struct device_area dev_area;
1994 : : char *id_str;
1995 : : struct id id;
1996 : :
1997 [ # # ]: 0 : if (!(cn = cn->child)) {
1998 : 0 : log_error("Empty metadata disk_area section of config file");
1999 : 0 : return 0;
2000 : : }
2001 : :
2002 [ # # ]: 0 : if (!get_config_uint64(cn, "start_sector", &dev_area.start)) {
2003 : 0 : log_error("Missing start_sector in metadata disk_area section "
2004 : : "of config file");
2005 : 0 : return 0;
2006 : : }
2007 : 0 : dev_area.start <<= SECTOR_SHIFT;
2008 : :
2009 [ # # ]: 0 : if (!get_config_uint64(cn, "size", &dev_area.size)) {
2010 : 0 : log_error("Missing size in metadata disk_area section "
2011 : : "of config file");
2012 : 0 : return 0;
2013 : : }
2014 : 0 : dev_area.size <<= SECTOR_SHIFT;
2015 : :
2016 [ # # ]: 0 : if (!get_config_str(cn, "id", &id_str)) {
2017 : 0 : log_error("Missing uuid in metadata disk_area section "
2018 : : "of config file");
2019 : 0 : return 0;
2020 : : }
2021 : :
2022 [ # # ]: 0 : if (!id_read_format(&id, id_str)) {
2023 : 0 : log_error("Invalid uuid in metadata disk_area section "
2024 : : "of config file: %s", id_str);
2025 : 0 : return 0;
2026 : : }
2027 : :
2028 [ # # ]: 0 : if (!(dev_area.dev = device_from_pvid(cmd, &id, NULL))) {
2029 : : char buffer[64] __attribute((aligned(8)));
2030 : :
2031 [ # # ]: 0 : if (!id_write_format(&id, buffer, sizeof(buffer)))
2032 : 0 : log_error("Couldn't find device.");
2033 : : else
2034 : 0 : log_error("Couldn't find device with uuid '%s'.",
2035 : : buffer);
2036 : :
2037 : 0 : return 0;
2038 : : }
2039 : :
2040 : 0 : return _add_raw(raw_list, &dev_area);
2041 : : }
2042 : :
2043 : 3 : struct format_type *create_text_format(struct cmd_context *cmd)
2044 : : {
2045 : : struct format_type *fmt;
2046 : : struct config_node *cn;
2047 : : struct config_value *cv;
2048 : : struct mda_lists *mda_lists;
2049 : :
2050 [ - + ]: 3 : if (!(fmt = dm_malloc(sizeof(*fmt))))
2051 : 0 : return_NULL;
2052 : :
2053 : 3 : fmt->cmd = cmd;
2054 : 3 : fmt->ops = &_text_handler;
2055 : 3 : fmt->name = FMT_TEXT_NAME;
2056 : 3 : fmt->alias = FMT_TEXT_ALIAS;
2057 : 3 : fmt->orphan_vg_name = ORPHAN_VG_NAME(FMT_TEXT_NAME);
2058 : 3 : fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_PRECOMMIT |
2059 : : FMT_UNLIMITED_VOLS | FMT_RESIZE_PV |
2060 : : FMT_UNLIMITED_STRIPESIZE;
2061 : :
2062 [ - + ]: 3 : if (!(mda_lists = dm_malloc(sizeof(struct mda_lists)))) {
2063 : 0 : log_error("Failed to allocate dir_list");
2064 : 0 : dm_free(fmt);
2065 : 0 : return NULL;
2066 : : }
2067 : :
2068 : 3 : dm_list_init(&mda_lists->dirs);
2069 : 3 : dm_list_init(&mda_lists->raws);
2070 : 3 : mda_lists->file_ops = &_metadata_text_file_ops;
2071 : 3 : mda_lists->raw_ops = &_metadata_text_raw_ops;
2072 : 3 : fmt->private = (void *) mda_lists;
2073 : :
2074 [ - + ]: 3 : if (!(fmt->labeller = text_labeller_create(fmt))) {
2075 : 0 : log_error("Couldn't create text label handler.");
2076 : 0 : dm_free(fmt);
2077 : 0 : return NULL;
2078 : : }
2079 : :
2080 [ - + ]: 3 : if (!(label_register_handler(FMT_TEXT_NAME, fmt->labeller))) {
2081 : 0 : log_error("Couldn't register text label handler.");
2082 : 0 : dm_free(fmt);
2083 : 0 : return NULL;
2084 : : }
2085 : :
2086 [ - + ]: 3 : if ((cn = find_config_tree_node(cmd, "metadata/dirs"))) {
2087 [ # # ]: 0 : for (cv = cn->v; cv; cv = cv->next) {
2088 [ # # ]: 0 : if (cv->type != CFG_STRING) {
2089 : 0 : log_error("Invalid string in config file: "
2090 : : "metadata/dirs");
2091 : 0 : goto err;
2092 : : }
2093 : :
2094 [ # # ]: 0 : if (!_add_dir(cv->v.str, &mda_lists->dirs)) {
2095 : 0 : log_error("Failed to add %s to text format "
2096 : : "metadata directory list ", cv->v.str);
2097 : 0 : goto err;
2098 : : }
2099 : : }
2100 : : }
2101 : :
2102 [ - + ]: 3 : if ((cn = find_config_tree_node(cmd, "metadata/disk_areas"))) {
2103 [ # # ]: 0 : for (cn = cn->child; cn; cn = cn->sib) {
2104 [ # # ]: 0 : if (!_get_config_disk_area(cmd, cn, &mda_lists->raws))
2105 : 0 : goto err;
2106 : : }
2107 : : }
2108 : :
2109 : 3 : log_very_verbose("Initialised format: %s", fmt->name);
2110 : :
2111 : 3 : return fmt;
2112 : :
2113 : : err:
2114 : 0 : _free_dirs(&mda_lists->dirs);
2115 : :
2116 : 0 : dm_free(fmt);
2117 : 3 : return NULL;
2118 : : }
|