xref: /dragonfly/contrib/lvm2/dist/lib/format_pool/disk_rep.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1 /*        $NetBSD: disk_rep.c,v 1.1.1.2 2009/12/02 00:26:50 haad Exp $          */
2 
3 /*
4  * Copyright (C) 1997-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 "label.h"
20 #include "metadata.h"
21 #include "lvmcache.h"
22 #include "filter.h"
23 #include "xlate.h"
24 #include "disk_rep.h"
25 
26 #include <assert.h>
27 
28 /* FIXME: memcpy might not be portable */
29 #define CPIN_8(x, y, z) {memcpy((x), (y), (z));}
30 #define CPOUT_8(x, y, z) {memcpy((y), (x), (z));}
31 #define CPIN_16(x, y) {(x) = xlate16_be((y));}
32 #define CPOUT_16(x, y) {(y) = xlate16_be((x));}
33 #define CPIN_32(x, y) {(x) = xlate32_be((y));}
34 #define CPOUT_32(x, y) {(y) = xlate32_be((x));}
35 #define CPIN_64(x, y) {(x) = xlate64_be((y));}
36 #define CPOUT_64(x, y) {(y) = xlate64_be((x));}
37 
__read_pool_disk(const struct format_type * fmt,struct device * dev,struct dm_pool * mem __attribute ((unused)),struct pool_list * pl,const char * vg_name __attribute ((unused)))38 static int __read_pool_disk(const struct format_type *fmt, struct device *dev,
39                                   struct dm_pool *mem __attribute((unused)), struct pool_list *pl,
40                                   const char *vg_name __attribute((unused)))
41 {
42           char buf[512] __attribute((aligned(8)));
43 
44           /* FIXME: Need to check the cache here first */
45           if (!dev_read(dev, UINT64_C(0), 512, buf)) {
46                     log_very_verbose("Failed to read PV data from %s",
47                                          dev_name(dev));
48                     return 0;
49           }
50 
51           if (!read_pool_label(pl, fmt->labeller, dev, buf, NULL))
52                     return_0;
53 
54           return 1;
55 }
56 
_add_pl_to_list(struct dm_list * head,struct pool_list * data)57 static void _add_pl_to_list(struct dm_list *head, struct pool_list *data)
58 {
59           struct pool_list *pl;
60 
61           dm_list_iterate_items(pl, head) {
62                     if (id_equal(&data->pv_uuid, &pl->pv_uuid)) {
63                               char uuid[ID_LEN + 7] __attribute((aligned(8)));
64 
65                               id_write_format(&pl->pv_uuid, uuid, ID_LEN + 7);
66 
67                               if (!dev_subsystem_part_major(data->dev)) {
68                                         log_very_verbose("Ignoring duplicate PV %s on "
69                                                              "%s", uuid,
70                                                              dev_name(data->dev));
71                                         return;
72                               }
73                               log_very_verbose("Duplicate PV %s - using %s %s",
74                                                    uuid, dev_subsystem_name(data->dev),
75                                                    dev_name(data->dev));
76                               dm_list_del(&pl->list);
77                               break;
78                     }
79           }
80           dm_list_add(head, &data->list);
81 }
82 
read_pool_label(struct pool_list * pl,struct labeller * l,struct device * dev,char * buf,struct label ** label)83 int read_pool_label(struct pool_list *pl, struct labeller *l,
84                         struct device *dev, char *buf, struct label **label)
85 {
86           struct lvmcache_info *info;
87           struct id pvid;
88           struct id vgid;
89           char uuid[ID_LEN + 7] __attribute((aligned(8)));
90           struct pool_disk *pd = &pl->pd;
91 
92           pool_label_in(pd, buf);
93 
94           get_pool_pv_uuid(&pvid, pd);
95           id_write_format(&pvid, uuid, ID_LEN + 7);
96           log_debug("Calculated uuid %s for %s", uuid, dev_name(dev));
97 
98           get_pool_vg_uuid(&vgid, pd);
99           id_write_format(&vgid, uuid, ID_LEN + 7);
100           log_debug("Calculated uuid %s for %s", uuid, pd->pl_pool_name);
101 
102           if (!(info = lvmcache_add(l, (char *) &pvid, dev, pd->pl_pool_name,
103                                           (char *) &vgid, 0)))
104                     return_0;
105           if (label)
106                     *label = info->label;
107 
108           info->device_size = xlate32_be(pd->pl_blocks) << SECTOR_SHIFT;
109           dm_list_init(&info->mdas);
110 
111           info->status &= ~CACHE_INVALID;
112 
113           pl->dev = dev;
114           pl->pv = NULL;
115           memcpy(&pl->pv_uuid, &pvid, sizeof(pvid));
116 
117           return 1;
118 }
119 
120 /**
121  * pool_label_out - copies a pool_label_t into a char buffer
122  * @pl: ptr to a pool_label_t struct
123  * @buf: ptr to raw space where label info will be copied
124  *
125  * This function is important because it takes care of all of
126  * the endian issues when copying to disk.  This way, when
127  * machines of different architectures are used, they will
128  * be able to interpret ondisk labels correctly.  Always use
129  * this function before writing to disk.
130  */
pool_label_out(struct pool_disk * pl,void * buf)131 void pool_label_out(struct pool_disk *pl, void *buf)
132 {
133           struct pool_disk *bufpl = (struct pool_disk *) buf;
134 
135           CPOUT_64(pl->pl_magic, bufpl->pl_magic);
136           CPOUT_64(pl->pl_pool_id, bufpl->pl_pool_id);
137           CPOUT_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE);
138           CPOUT_32(pl->pl_version, bufpl->pl_version);
139           CPOUT_32(pl->pl_subpools, bufpl->pl_subpools);
140           CPOUT_32(pl->pl_sp_id, bufpl->pl_sp_id);
141           CPOUT_32(pl->pl_sp_devs, bufpl->pl_sp_devs);
142           CPOUT_32(pl->pl_sp_devid, bufpl->pl_sp_devid);
143           CPOUT_32(pl->pl_sp_type, bufpl->pl_sp_type);
144           CPOUT_64(pl->pl_blocks, bufpl->pl_blocks);
145           CPOUT_32(pl->pl_striping, bufpl->pl_striping);
146           CPOUT_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs);
147           CPOUT_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid);
148           CPOUT_32(pl->pl_sp_weight, bufpl->pl_sp_weight);
149           CPOUT_32(pl->pl_minor, bufpl->pl_minor);
150           CPOUT_32(pl->pl_padding, bufpl->pl_padding);
151           CPOUT_8(pl->pl_reserve, bufpl->pl_reserve, 184);
152 }
153 
154 /**
155  * pool_label_in - copies a char buffer into a pool_label_t
156  * @pl: ptr to a pool_label_t struct
157  * @buf: ptr to raw space where label info is copied from
158  *
159  * This function is important because it takes care of all of
160  * the endian issues when information from disk is about to be
161  * used.  This way, when machines of different architectures
162  * are used, they will be able to interpret ondisk labels
163  * correctly.  Always use this function before using labels that
164  * were read from disk.
165  */
pool_label_in(struct pool_disk * pl,void * buf)166 void pool_label_in(struct pool_disk *pl, void *buf)
167 {
168           struct pool_disk *bufpl = (struct pool_disk *) buf;
169 
170           CPIN_64(pl->pl_magic, bufpl->pl_magic);
171           CPIN_64(pl->pl_pool_id, bufpl->pl_pool_id);
172           CPIN_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE);
173           CPIN_32(pl->pl_version, bufpl->pl_version);
174           CPIN_32(pl->pl_subpools, bufpl->pl_subpools);
175           CPIN_32(pl->pl_sp_id, bufpl->pl_sp_id);
176           CPIN_32(pl->pl_sp_devs, bufpl->pl_sp_devs);
177           CPIN_32(pl->pl_sp_devid, bufpl->pl_sp_devid);
178           CPIN_32(pl->pl_sp_type, bufpl->pl_sp_type);
179           CPIN_64(pl->pl_blocks, bufpl->pl_blocks);
180           CPIN_32(pl->pl_striping, bufpl->pl_striping);
181           CPIN_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs);
182           CPIN_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid);
183           CPIN_32(pl->pl_sp_weight, bufpl->pl_sp_weight);
184           CPIN_32(pl->pl_minor, bufpl->pl_minor);
185           CPIN_32(pl->pl_padding, bufpl->pl_padding);
186           CPIN_8(pl->pl_reserve, bufpl->pl_reserve, 184);
187 }
188 
_calc_char(unsigned int id)189 static char _calc_char(unsigned int id)
190 {
191           /*
192            * [0-9A-Za-z!#] - 64 printable chars (6-bits)
193            */
194 
195           if (id < 10)
196                     return id + 48;
197           if (id < 36)
198                     return (id - 10) + 65;
199           if (id < 62)
200                     return (id - 36) + 97;
201           if (id == 62)
202                     return '!';
203           if (id == 63)
204                     return '#';
205 
206           return '%';
207 }
208 
get_pool_uuid(char * uuid,uint64_t poolid,uint32_t spid,uint32_t devid)209 void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid)
210 {
211           int i;
212           unsigned shifter = 0x003F;
213 
214           assert(ID_LEN == 32);
215           memset(uuid, 0, ID_LEN);
216           strcat(uuid, "POOL0000000000");
217 
218           /* We grab the entire 64 bits (+2 that get shifted in) */
219           for (i = 13; i < 24; i++) {
220                     uuid[i] = _calc_char(((unsigned) poolid) & shifter);
221                     poolid = poolid >> 6;
222           }
223 
224           /* We grab the entire 32 bits (+4 that get shifted in) */
225           for (i = 24; i < 30; i++) {
226                     uuid[i] = _calc_char((unsigned) (spid & shifter));
227                     spid = spid >> 6;
228           }
229 
230           /*
231            * Since we can only have 128 devices, we only worry about the
232            * last 12 bits
233            */
234           for (i = 30; i < 32; i++) {
235                     uuid[i] = _calc_char((unsigned) (devid & shifter));
236                     devid = devid >> 6;
237           }
238 
239 }
240 
_read_vg_pds(const struct format_type * fmt,struct dm_pool * mem,struct lvmcache_vginfo * vginfo,struct dm_list * head,uint32_t * devcount)241 static int _read_vg_pds(const struct format_type *fmt, struct dm_pool *mem,
242                               struct lvmcache_vginfo *vginfo, struct dm_list *head,
243                               uint32_t *devcount)
244 {
245           struct lvmcache_info *info;
246           struct pool_list *pl = NULL;
247           struct dm_pool *tmpmem;
248 
249           uint32_t sp_count = 0;
250           uint32_t *sp_devs = NULL;
251           uint32_t i;
252 
253           /* FIXME: maybe should return a different error in memory
254            * allocation failure */
255           if (!(tmpmem = dm_pool_create("pool read_vg", 512)))
256                     return_0;
257 
258           dm_list_iterate_items(info, &vginfo->infos) {
259                     if (info->dev &&
260                         !(pl = read_pool_disk(fmt, info->dev, mem, vginfo->vgname)))
261                                   break;
262                     /*
263                      * We need to keep track of the total expected number
264                      * of devices per subpool
265                      */
266                     if (!sp_count) {
267                               /* FIXME pl left uninitialised if !info->dev */
268                               sp_count = pl->pd.pl_subpools;
269                               if (!(sp_devs =
270                                     dm_pool_zalloc(tmpmem,
271                                                     sizeof(uint32_t) * sp_count))) {
272                                         log_error("Unable to allocate %d 32-bit uints",
273                                                     sp_count);
274                                         dm_pool_destroy(tmpmem);
275                                         return 0;
276                               }
277                     }
278                     /*
279                      * watch out for a pool label with a different subpool
280                      * count than the original - give up if it does
281                      */
282                     if (sp_count != pl->pd.pl_subpools)
283                               break;
284 
285                     _add_pl_to_list(head, pl);
286 
287                     if (sp_count > pl->pd.pl_sp_id && sp_devs[pl->pd.pl_sp_id] == 0)
288                               sp_devs[pl->pd.pl_sp_id] = pl->pd.pl_sp_devs;
289           }
290 
291           *devcount = 0;
292           for (i = 0; i < sp_count; i++)
293                     *devcount += sp_devs[i];
294 
295           dm_pool_destroy(tmpmem);
296 
297           if (pl && *pl->pd.pl_pool_name)
298                     return 1;
299 
300           return 0;
301 
302 }
303 
read_pool_pds(const struct format_type * fmt,const char * vg_name,struct dm_pool * mem,struct dm_list * pdhead)304 int read_pool_pds(const struct format_type *fmt, const char *vg_name,
305                       struct dm_pool *mem, struct dm_list *pdhead)
306 {
307           struct lvmcache_vginfo *vginfo;
308           uint32_t totaldevs;
309           int full_scan = -1;
310 
311           do {
312                     /*
313                      * If the cache scanning doesn't work, this will never work
314                      */
315                     if (vg_name && (vginfo = vginfo_from_vgname(vg_name, NULL)) &&
316                         vginfo->infos.n) {
317 
318                               if (_read_vg_pds(fmt, mem, vginfo, pdhead, &totaldevs)) {
319                                         /*
320                                          * If we found all the devices we were
321                                          * expecting, return success
322                                          */
323                                         if (dm_list_size(pdhead) == totaldevs)
324                                                   return 1;
325 
326                                         /*
327                                          * accept partial pool if we've done a full
328                                          * rescan of the cache
329                                          */
330                                         if (full_scan > 0)
331                                                   return 1;
332                               }
333                     }
334                     /* Failed */
335                     dm_list_init(pdhead);
336 
337                     full_scan++;
338                     if (full_scan > 1) {
339                               log_debug("No devices for vg %s found in cache",
340                                           vg_name);
341                               return 0;
342                     }
343                     lvmcache_label_scan(fmt->cmd, full_scan);
344 
345           } while (1);
346 
347 }
348 
read_pool_disk(const struct format_type * fmt,struct device * dev,struct dm_pool * mem,const char * vg_name)349 struct pool_list *read_pool_disk(const struct format_type *fmt,
350                                          struct device *dev, struct dm_pool *mem,
351                                          const char *vg_name)
352 {
353           struct pool_list *pl;
354 
355           if (!dev_open(dev))
356                     return_NULL;
357 
358           if (!(pl = dm_pool_zalloc(mem, sizeof(*pl)))) {
359                     log_error("Unable to allocate pool list structure");
360                     return 0;
361           }
362 
363           if (!__read_pool_disk(fmt, dev, mem, pl, vg_name))
364                     return_NULL;
365 
366           if (!dev_close(dev))
367                     stack;
368 
369           return pl;
370 
371 }
372