1 /*        $NetBSD: text_label.c,v 1.1.1.2 2009/12/02 00:26:28 haad Exp $        */
2 
3 /*
4  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
6  *
7  * This file is part of LVM2.
8  *
9  * This copyrighted material is made available to anyone wishing to use,
10  * modify, copy, or redistribute it subject to the terms and conditions
11  * of the GNU Lesser General Public License v.2.1.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17 
18 #include "lib.h"
19 #include "format-text.h"
20 #include "layout.h"
21 #include "label.h"
22 #include "xlate.h"
23 #include "lvmcache.h"
24 
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 
_text_can_handle(struct labeller * l __attribute ((unused)),void * buf,uint64_t sector __attribute ((unused)))28 static int _text_can_handle(struct labeller *l __attribute((unused)),
29                                   void *buf,
30                                   uint64_t sector __attribute((unused)))
31 {
32           struct label_header *lh = (struct label_header *) buf;
33 
34           if (!strncmp((char *)lh->type, LVM2_LABEL, sizeof(lh->type)))
35                     return 1;
36 
37           return 0;
38 }
39 
_text_write(struct label * label,void * buf)40 static int _text_write(struct label *label, void *buf)
41 {
42           struct label_header *lh = (struct label_header *) buf;
43           struct pv_header *pvhdr;
44           struct lvmcache_info *info;
45           struct disk_locn *pvh_dlocn_xl;
46           struct metadata_area *mda;
47           struct mda_context *mdac;
48           struct data_area_list *da;
49           char buffer[64] __attribute((aligned(8)));
50           int da1, mda1, mda2;
51 
52           /* FIXME Move to where label is created */
53           strncpy(label->type, LVM2_LABEL, sizeof(label->type));
54 
55           strncpy((char *)lh->type, label->type, sizeof(label->type));
56 
57           pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
58           info = (struct lvmcache_info *) label->info;
59           pvhdr->device_size_xl = xlate64(info->device_size);
60           memcpy(pvhdr->pv_uuid, &info->dev->pvid, sizeof(struct id));
61           if (!id_write_format((const struct id *)pvhdr->pv_uuid, buffer,
62                                    sizeof(buffer))) {
63                     stack;
64                     buffer[0] = '\0';
65           }
66 
67           pvh_dlocn_xl = &pvhdr->disk_areas_xl[0];
68 
69           /* List of data areas (holding PEs) */
70           dm_list_iterate_items(da, &info->das) {
71                     pvh_dlocn_xl->offset = xlate64(da->disk_locn.offset);
72                     pvh_dlocn_xl->size = xlate64(da->disk_locn.size);
73                     pvh_dlocn_xl++;
74           }
75 
76           /* NULL-termination */
77           pvh_dlocn_xl->offset = xlate64(UINT64_C(0));
78           pvh_dlocn_xl->size = xlate64(UINT64_C(0));
79           pvh_dlocn_xl++;
80 
81           /* List of metadata area header locations */
82           dm_list_iterate_items(mda, &info->mdas) {
83                     mdac = (struct mda_context *) mda->metadata_locn;
84 
85                     if (mdac->area.dev != info->dev)
86                               continue;
87 
88                     pvh_dlocn_xl->offset = xlate64(mdac->area.start);
89                     pvh_dlocn_xl->size = xlate64(mdac->area.size);
90                     pvh_dlocn_xl++;
91           }
92 
93           /* NULL-termination */
94           pvh_dlocn_xl->offset = xlate64(UINT64_C(0));
95           pvh_dlocn_xl->size = xlate64(UINT64_C(0));
96 
97           /* Create debug message with da and mda locations */
98           if (xlate64(pvhdr->disk_areas_xl[0].offset) ||
99               xlate64(pvhdr->disk_areas_xl[0].size))
100                     da1 = 0;
101           else
102                     da1 = -1;
103 
104           mda1 = da1 + 2;
105           mda2 = mda1 + 1;
106 
107           if (!xlate64(pvhdr->disk_areas_xl[mda1].offset) &&
108               !xlate64(pvhdr->disk_areas_xl[mda1].size))
109                     mda1 = mda2 = 0;
110           else if (!xlate64(pvhdr->disk_areas_xl[mda2].offset) &&
111                      !xlate64(pvhdr->disk_areas_xl[mda2].size))
112                     mda2 = 0;
113 
114           log_debug("%s: Preparing PV label header %s size %" PRIu64 " with"
115                       "%s%.*" PRIu64 "%s%.*" PRIu64 "%s"
116                       "%s%.*" PRIu64 "%s%.*" PRIu64 "%s"
117                       "%s%.*" PRIu64 "%s%.*" PRIu64 "%s",
118                       dev_name(info->dev), buffer, info->device_size,
119                       (da1 > -1) ? " da1 (" : "",
120                       (da1 > -1) ? 1 : 0,
121                       (da1 > -1) ? xlate64(pvhdr->disk_areas_xl[da1].offset) >> SECTOR_SHIFT : 0,
122                       (da1 > -1) ? "s, " : "",
123                       (da1 > -1) ? 1 : 0,
124                       (da1 > -1) ? xlate64(pvhdr->disk_areas_xl[da1].size) >> SECTOR_SHIFT : 0,
125                       (da1 > -1) ? "s)" : "",
126                       mda1 ? " mda1 (" : "",
127                       mda1 ? 1 : 0,
128                       mda1 ? xlate64(pvhdr->disk_areas_xl[mda1].offset) >> SECTOR_SHIFT : 0,
129                       mda1 ? "s, " : "",
130                       mda1 ? 1 : 0,
131                       mda1 ? xlate64(pvhdr->disk_areas_xl[mda1].size) >> SECTOR_SHIFT : 0,
132                       mda1 ? "s)" : "",
133                       mda2 ? " mda2 (" : "",
134                       mda2 ? 1 : 0,
135                       mda2 ? xlate64(pvhdr->disk_areas_xl[mda2].offset) >> SECTOR_SHIFT : 0,
136                       mda2 ? "s, " : "",
137                       mda2 ? 1 : 0,
138                       mda2 ? xlate64(pvhdr->disk_areas_xl[mda2].size) >> SECTOR_SHIFT : 0,
139                       mda2 ? "s)" : "");
140 
141           if (da1 < 0) {
142                     log_error("Internal error: %s label header currently requires "
143                                 "a data area.", dev_name(info->dev));
144                     return 0;
145           }
146 
147           return 1;
148 }
149 
add_da(struct dm_pool * mem,struct dm_list * das,uint64_t start,uint64_t size)150 int add_da(struct dm_pool *mem, struct dm_list *das,
151              uint64_t start, uint64_t size)
152 {
153           struct data_area_list *dal;
154 
155           if (!mem) {
156                     if (!(dal = dm_malloc(sizeof(*dal)))) {
157                               log_error("struct data_area_list allocation failed");
158                               return 0;
159                     }
160           } else {
161                     if (!(dal = dm_pool_alloc(mem, sizeof(*dal)))) {
162                               log_error("struct data_area_list allocation failed");
163                               return 0;
164                     }
165           }
166 
167           dal->disk_locn.offset = start;
168           dal->disk_locn.size = size;
169 
170           dm_list_add(das, &dal->list);
171 
172           return 1;
173 }
174 
del_das(struct dm_list * das)175 void del_das(struct dm_list *das)
176 {
177           struct dm_list *dah, *tmp;
178           struct data_area_list *da;
179 
180           dm_list_iterate_safe(dah, tmp, das) {
181                     da = dm_list_item(dah, struct data_area_list);
182                     dm_list_del(&da->list);
183                     dm_free(da);
184           }
185 }
186 
add_mda(const struct format_type * fmt,struct dm_pool * mem,struct dm_list * mdas,struct device * dev,uint64_t start,uint64_t size)187 int add_mda(const struct format_type *fmt, struct dm_pool *mem, struct dm_list *mdas,
188               struct device *dev, uint64_t start, uint64_t size)
189 {
190 /* FIXME List size restricted by pv_header SECTOR_SIZE */
191           struct metadata_area *mdal;
192           struct mda_lists *mda_lists = (struct mda_lists *) fmt->private;
193           struct mda_context *mdac;
194 
195           if (!mem) {
196                     if (!(mdal = dm_malloc(sizeof(struct metadata_area)))) {
197                               log_error("struct mda_list allocation failed");
198                               return 0;
199                     }
200 
201                     if (!(mdac = dm_malloc(sizeof(struct mda_context)))) {
202                               log_error("struct mda_context allocation failed");
203                               dm_free(mdal);
204                               return 0;
205                     }
206           } else {
207                     if (!(mdal = dm_pool_alloc(mem, sizeof(struct metadata_area)))) {
208                               log_error("struct mda_list allocation failed");
209                               return 0;
210                     }
211 
212                     if (!(mdac = dm_pool_alloc(mem, sizeof(struct mda_context)))) {
213                               log_error("struct mda_context allocation failed");
214                               return 0;
215                     }
216           }
217 
218           mdal->ops = mda_lists->raw_ops;
219           mdal->metadata_locn = mdac;
220 
221           mdac->area.dev = dev;
222           mdac->area.start = start;
223           mdac->area.size = size;
224           mdac->free_sectors = UINT64_C(0);
225           memset(&mdac->rlocn, 0, sizeof(mdac->rlocn));
226 
227           dm_list_add(mdas, &mdal->list);
228           return 1;
229 }
230 
del_mdas(struct dm_list * mdas)231 void del_mdas(struct dm_list *mdas)
232 {
233           struct dm_list *mdah, *tmp;
234           struct metadata_area *mda;
235 
236           dm_list_iterate_safe(mdah, tmp, mdas) {
237                     mda = dm_list_item(mdah, struct metadata_area);
238                     dm_free(mda->metadata_locn);
239                     dm_list_del(&mda->list);
240                     dm_free(mda);
241           }
242 }
243 
_text_initialise_label(struct labeller * l __attribute ((unused)),struct label * label)244 static int _text_initialise_label(struct labeller *l __attribute((unused)),
245                                           struct label *label)
246 {
247           strncpy(label->type, LVM2_LABEL, sizeof(label->type));
248 
249           return 1;
250 }
251 
_text_read(struct labeller * l,struct device * dev,void * buf,struct label ** label)252 static int _text_read(struct labeller *l, struct device *dev, void *buf,
253                      struct label **label)
254 {
255           struct label_header *lh = (struct label_header *) buf;
256           struct pv_header *pvhdr;
257           struct lvmcache_info *info;
258           struct disk_locn *dlocn_xl;
259           uint64_t offset;
260           struct metadata_area *mda;
261           struct id vgid;
262           struct mda_context *mdac;
263           const char *vgname;
264           uint32_t vgstatus;
265           char *creation_host;
266 
267           pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
268 
269           if (!(info = lvmcache_add(l, (char *)pvhdr->pv_uuid, dev,
270                                           FMT_TEXT_ORPHAN_VG_NAME,
271                                           FMT_TEXT_ORPHAN_VG_NAME, 0)))
272                     return_0;
273           *label = info->label;
274 
275           info->device_size = xlate64(pvhdr->device_size_xl);
276 
277           if (info->das.n)
278                     del_das(&info->das);
279           dm_list_init(&info->das);
280 
281           if (info->mdas.n)
282                     del_mdas(&info->mdas);
283           dm_list_init(&info->mdas);
284 
285           /* Data areas holding the PEs */
286           dlocn_xl = pvhdr->disk_areas_xl;
287           while ((offset = xlate64(dlocn_xl->offset))) {
288                     add_da(NULL, &info->das, offset,
289                            xlate64(dlocn_xl->size));
290                     dlocn_xl++;
291           }
292 
293           /* Metadata area headers */
294           dlocn_xl++;
295           while ((offset = xlate64(dlocn_xl->offset))) {
296                     add_mda(info->fmt, NULL, &info->mdas, dev, offset,
297                               xlate64(dlocn_xl->size));
298                     dlocn_xl++;
299           }
300 
301           dm_list_iterate_items(mda, &info->mdas) {
302                     mdac = (struct mda_context *) mda->metadata_locn;
303                     if ((vgname = vgname_from_mda(info->fmt, &mdac->area,
304                                                         &vgid, &vgstatus, &creation_host,
305                                                         &mdac->free_sectors)) &&
306                         !lvmcache_update_vgname_and_id(info, vgname,
307                                                                (char *) &vgid, vgstatus,
308                                                                creation_host))
309                               return_0;
310           }
311 
312           info->status &= ~CACHE_INVALID;
313 
314           return 1;
315 }
316 
_text_destroy_label(struct labeller * l __attribute ((unused)),struct label * label)317 static void _text_destroy_label(struct labeller *l __attribute((unused)),
318                                         struct label *label)
319 {
320           struct lvmcache_info *info = (struct lvmcache_info *) label->info;
321 
322           if (info->mdas.n)
323                     del_mdas(&info->mdas);
324           if (info->das.n)
325                     del_das(&info->das);
326 }
327 
_fmt_text_destroy(struct labeller * l)328 static void _fmt_text_destroy(struct labeller *l)
329 {
330           dm_free(l);
331 }
332 
333 struct label_ops _text_ops = {
334           .can_handle = _text_can_handle,
335           .write = _text_write,
336           .read = _text_read,
337           .verify = _text_can_handle,
338           .initialise_label = _text_initialise_label,
339           .destroy_label = _text_destroy_label,
340           .destroy = _fmt_text_destroy,
341 };
342 
text_labeller_create(const struct format_type * fmt)343 struct labeller *text_labeller_create(const struct format_type *fmt)
344 {
345           struct labeller *l;
346 
347           if (!(l = dm_malloc(sizeof(*l)))) {
348                     log_error("Couldn't allocate labeller object.");
349                     return NULL;
350           }
351 
352           l->ops = &_text_ops;
353           l->private = (const void *) fmt;
354 
355           return l;
356 }
357