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 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 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 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 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 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 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 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 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 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 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 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