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