1 /* $NetBSD: report.c,v 1.1.1.2 2009/02/18 11:17:19 haad Exp $ */ 2 3 /* 4 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. 5 * Copyright (C) 2004-2007 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 "metadata.h" 20 #include "report.h" 21 #include "toolcontext.h" 22 #include "lvm-string.h" 23 #include "display.h" 24 #include "activate.h" 25 #include "segtype.h" 26 #include "str_list.h" 27 #include "lvmcache.h" 28 29 struct lvm_report_object { 30 struct volume_group *vg; 31 struct logical_volume *lv; 32 struct physical_volume *pv; 33 struct lv_segment *seg; 34 struct pv_segment *pvseg; 35 }; 36 37 /* 38 * For macro use 39 */ 40 static union { 41 struct physical_volume _pv; 42 struct logical_volume _lv; 43 struct volume_group _vg; 44 struct lv_segment _seg; 45 struct pv_segment _pvseg; 46 } _dummy; 47 48 static char _alloc_policy_char(alloc_policy_t alloc) 49 { 50 switch (alloc) { 51 case ALLOC_CONTIGUOUS: 52 return 'c'; 53 case ALLOC_CLING: 54 return 'l'; 55 case ALLOC_NORMAL: 56 return 'n'; 57 case ALLOC_ANYWHERE: 58 return 'a'; 59 default: 60 return 'i'; 61 } 62 } 63 64 static const uint64_t _minusone = UINT64_C(-1); 65 66 /* 67 * Data-munging functions to prepare each data type for display and sorting 68 */ 69 static int _string_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), 70 struct dm_report_field *field, 71 const void *data, void *private __attribute((unused))) 72 { 73 return dm_report_field_string(rh, field, (const char **) data); 74 } 75 76 static int _dev_name_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), 77 struct dm_report_field *field, 78 const void *data, void *private __attribute((unused))) 79 { 80 const char *name = dev_name(*(const struct device **) data); 81 82 return dm_report_field_string(rh, field, &name); 83 } 84 85 static int _format_pvsegs(struct dm_pool *mem, struct dm_report_field *field, 86 const void *data, int range_format) 87 { 88 const struct lv_segment *seg = (const struct lv_segment *) data; 89 unsigned int s; 90 const char *name = NULL; 91 uint32_t extent = 0; 92 char extent_str[32]; 93 94 if (!dm_pool_begin_object(mem, 256)) { 95 log_error("dm_pool_begin_object failed"); 96 return 0; 97 } 98 99 for (s = 0; s < seg->area_count; s++) { 100 switch (seg_type(seg, s)) { 101 case AREA_LV: 102 name = seg_lv(seg, s)->name; 103 extent = seg_le(seg, s); 104 break; 105 case AREA_PV: 106 name = dev_name(seg_dev(seg, s)); 107 extent = seg_pe(seg, s); 108 break; 109 case AREA_UNASSIGNED: 110 name = "unassigned"; 111 extent = 0; 112 } 113 114 if (!dm_pool_grow_object(mem, name, strlen(name))) { 115 log_error("dm_pool_grow_object failed"); 116 return 0; 117 } 118 119 if (dm_snprintf(extent_str, sizeof(extent_str), 120 "%s%" PRIu32 "%s", 121 range_format ? ":" : "(", extent, 122 range_format ? "-" : ")") < 0) { 123 log_error("Extent number dm_snprintf failed"); 124 return 0; 125 } 126 if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) { 127 log_error("dm_pool_grow_object failed"); 128 return 0; 129 } 130 131 if (range_format) { 132 if (dm_snprintf(extent_str, sizeof(extent_str), 133 "%" PRIu32, extent + seg->area_len - 1) < 0) { 134 log_error("Extent number dm_snprintf failed"); 135 return 0; 136 } 137 if (!dm_pool_grow_object(mem, extent_str, strlen(extent_str))) { 138 log_error("dm_pool_grow_object failed"); 139 return 0; 140 } 141 } 142 143 if ((s != seg->area_count - 1) && 144 !dm_pool_grow_object(mem, range_format ? " " : ",", 1)) { 145 log_error("dm_pool_grow_object failed"); 146 return 0; 147 } 148 } 149 150 if (!dm_pool_grow_object(mem, "\0", 1)) { 151 log_error("dm_pool_grow_object failed"); 152 return 0; 153 } 154 155 dm_report_field_set_value(field, dm_pool_end_object(mem), NULL); 156 157 return 1; 158 } 159 160 static int _devices_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 161 struct dm_report_field *field, 162 const void *data, void *private __attribute((unused))) 163 { 164 return _format_pvsegs(mem, field, data, 0); 165 } 166 167 static int _peranges_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 168 struct dm_report_field *field, 169 const void *data, void *private __attribute((unused))) 170 { 171 return _format_pvsegs(mem, field, data, 1); 172 } 173 174 static int _tags_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 175 struct dm_report_field *field, 176 const void *data, void *private __attribute((unused))) 177 { 178 const struct dm_list *tags = (const struct dm_list *) data; 179 struct str_list *sl; 180 181 if (!dm_pool_begin_object(mem, 256)) { 182 log_error("dm_pool_begin_object failed"); 183 return 0; 184 } 185 186 dm_list_iterate_items(sl, tags) { 187 if (!dm_pool_grow_object(mem, sl->str, strlen(sl->str)) || 188 (sl->list.n != tags && !dm_pool_grow_object(mem, ",", 1))) { 189 log_error("dm_pool_grow_object failed"); 190 return 0; 191 } 192 } 193 194 if (!dm_pool_grow_object(mem, "\0", 1)) { 195 log_error("dm_pool_grow_object failed"); 196 return 0; 197 } 198 199 dm_report_field_set_value(field, dm_pool_end_object(mem), NULL); 200 201 return 1; 202 } 203 204 static int _modules_disp(struct dm_report *rh, struct dm_pool *mem, 205 struct dm_report_field *field, 206 const void *data, void *private) 207 { 208 const struct logical_volume *lv = (const struct logical_volume *) data; 209 struct dm_list *modules; 210 211 if (!(modules = str_list_create(mem))) { 212 log_error("modules str_list allocation failed"); 213 return 0; 214 } 215 216 if (!list_lv_modules(mem, lv, modules)) 217 return_0; 218 219 return _tags_disp(rh, mem, field, modules, private); 220 } 221 222 static int _vgfmt_disp(struct dm_report *rh, struct dm_pool *mem, 223 struct dm_report_field *field, 224 const void *data, void *private) 225 { 226 const struct volume_group *vg = (const struct volume_group *) data; 227 228 if (!vg->fid) { 229 dm_report_field_set_value(field, "", NULL); 230 return 1; 231 } 232 233 return _string_disp(rh, mem, field, &vg->fid->fmt->name, private); 234 } 235 236 static int _pvfmt_disp(struct dm_report *rh, struct dm_pool *mem, 237 struct dm_report_field *field, 238 const void *data, void *private) 239 { 240 const struct physical_volume *pv = 241 (const struct physical_volume *) data; 242 243 if (!pv->fmt) { 244 dm_report_field_set_value(field, "", NULL); 245 return 1; 246 } 247 248 return _string_disp(rh, mem, field, &pv->fmt->name, private); 249 } 250 251 static int _lvkmaj_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), 252 struct dm_report_field *field, 253 const void *data, void *private __attribute((unused))) 254 { 255 const struct logical_volume *lv = (const struct logical_volume *) data; 256 struct lvinfo info; 257 258 if (lv_info(lv->vg->cmd, lv, &info, 0, 0) && info.exists) 259 return dm_report_field_int(rh, field, &info.major); 260 261 return dm_report_field_uint64(rh, field, &_minusone); 262 } 263 264 static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), 265 struct dm_report_field *field, 266 const void *data, void *private __attribute((unused))) 267 { 268 const struct logical_volume *lv = (const struct logical_volume *) data; 269 struct lvinfo info; 270 271 if (lv_info(lv->vg->cmd, lv, &info, 0, 0) && info.exists) 272 return dm_report_field_int(rh, field, &info.minor); 273 274 return dm_report_field_uint64(rh, field, &_minusone); 275 } 276 277 static int _lv_mimage_in_sync(const struct logical_volume *lv) 278 { 279 float percent; 280 struct lv_segment *mirror_seg = find_mirror_seg(first_seg(lv)); 281 282 if (!(lv->status & MIRROR_IMAGE) || !mirror_seg) 283 return_0; 284 285 if (!lv_mirror_percent(lv->vg->cmd, mirror_seg->lv, 0, &percent, NULL)) 286 return_0; 287 288 if (percent >= 100.0) 289 return 1; 290 291 return 0; 292 } 293 294 static int _lvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 295 struct dm_report_field *field, 296 const void *data, void *private __attribute((unused))) 297 { 298 const struct logical_volume *lv = (const struct logical_volume *) data; 299 struct lvinfo info; 300 char *repstr; 301 float snap_percent; 302 303 if (!(repstr = dm_pool_zalloc(mem, 7))) { 304 log_error("dm_pool_alloc failed"); 305 return 0; 306 } 307 308 /* Blank if this is a "free space" LV. */ 309 if (!*lv->name) 310 goto out; 311 312 if (lv->status & PVMOVE) 313 repstr[0] = 'p'; 314 else if (lv->status & CONVERTING) 315 repstr[0] = 'c'; 316 else if (lv->status & MIRRORED) { 317 if (lv->status & MIRROR_NOTSYNCED) 318 repstr[0] = 'M'; 319 else 320 repstr[0] = 'm'; 321 }else if (lv->status & MIRROR_IMAGE) 322 if (_lv_mimage_in_sync(lv)) 323 repstr[0] = 'i'; 324 else 325 repstr[0] = 'I'; 326 else if (lv->status & MIRROR_LOG) 327 repstr[0] = 'l'; 328 else if (lv->status & VIRTUAL) 329 repstr[0] = 'v'; 330 else if (lv_is_origin(lv)) 331 repstr[0] = 'o'; 332 else if (lv_is_cow(lv)) 333 repstr[0] = 's'; 334 else 335 repstr[0] = '-'; 336 337 if (lv->status & PVMOVE) 338 repstr[1] = '-'; 339 else if (lv->status & LVM_WRITE) 340 repstr[1] = 'w'; 341 else if (lv->status & LVM_READ) 342 repstr[1] = 'r'; 343 else 344 repstr[1] = '-'; 345 346 repstr[2] = _alloc_policy_char(lv->alloc); 347 348 if (lv->status & LOCKED) 349 repstr[2] = toupper(repstr[2]); 350 351 if (lv->status & FIXED_MINOR) 352 repstr[3] = 'm'; /* Fixed Minor */ 353 else 354 repstr[3] = '-'; 355 356 if (lv_info(lv->vg->cmd, lv, &info, 1, 0) && info.exists) { 357 if (info.suspended) 358 repstr[4] = 's'; /* Suspended */ 359 else if (info.live_table) 360 repstr[4] = 'a'; /* Active */ 361 else if (info.inactive_table) 362 repstr[4] = 'i'; /* Inactive with table */ 363 else 364 repstr[4] = 'd'; /* Inactive without table */ 365 366 /* Snapshot dropped? */ 367 if (info.live_table && lv_is_cow(lv) && 368 (!lv_snapshot_percent(lv, &snap_percent) || 369 snap_percent < 0 || snap_percent >= 100)) { 370 repstr[0] = toupper(repstr[0]); 371 if (info.suspended) 372 repstr[4] = 'S'; /* Susp Inv snapshot */ 373 else 374 repstr[4] = 'I'; /* Invalid snapshot */ 375 } 376 377 if (info.open_count) 378 repstr[5] = 'o'; /* Open */ 379 else 380 repstr[5] = '-'; 381 } else { 382 repstr[4] = '-'; 383 repstr[5] = '-'; 384 } 385 386 out: 387 dm_report_field_set_value(field, repstr, NULL); 388 return 1; 389 } 390 391 static int _pvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 392 struct dm_report_field *field, 393 const void *data, void *private __attribute((unused))) 394 { 395 const uint32_t status = *(const uint32_t *) data; 396 char *repstr; 397 398 if (!(repstr = dm_pool_zalloc(mem, 3))) { 399 log_error("dm_pool_alloc failed"); 400 return 0; 401 } 402 403 if (status & ALLOCATABLE_PV) 404 repstr[0] = 'a'; 405 else 406 repstr[0] = '-'; 407 408 if (status & EXPORTED_VG) 409 repstr[1] = 'x'; 410 else 411 repstr[1] = '-'; 412 413 dm_report_field_set_value(field, repstr, NULL); 414 return 1; 415 } 416 417 static int _vgstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 418 struct dm_report_field *field, 419 const void *data, void *private __attribute((unused))) 420 { 421 const struct volume_group *vg = (const struct volume_group *) data; 422 char *repstr; 423 424 if (!(repstr = dm_pool_zalloc(mem, 7))) { 425 log_error("dm_pool_alloc failed"); 426 return 0; 427 } 428 429 if (vg->status & LVM_WRITE) 430 repstr[0] = 'w'; 431 else 432 repstr[0] = 'r'; 433 434 if (vg->status & RESIZEABLE_VG) 435 repstr[1] = 'z'; 436 else 437 repstr[1] = '-'; 438 439 if (vg->status & EXPORTED_VG) 440 repstr[2] = 'x'; 441 else 442 repstr[2] = '-'; 443 444 if (vg_missing_pv_count(vg)) 445 repstr[3] = 'p'; 446 else 447 repstr[3] = '-'; 448 449 repstr[4] = _alloc_policy_char(vg->alloc); 450 451 if (vg_is_clustered(vg)) 452 repstr[5] = 'c'; 453 else 454 repstr[5] = '-'; 455 456 dm_report_field_set_value(field, repstr, NULL); 457 return 1; 458 } 459 460 static int _segtype_disp(struct dm_report *rh __attribute((unused)), 461 struct dm_pool *mem __attribute((unused)), 462 struct dm_report_field *field, 463 const void *data, void *private __attribute((unused))) 464 { 465 const struct lv_segment *seg = (const struct lv_segment *) data; 466 467 if (seg->area_count == 1) { 468 dm_report_field_set_value(field, "linear", NULL); 469 return 1; 470 } 471 472 dm_report_field_set_value(field, seg->segtype->ops->name(seg), NULL); 473 return 1; 474 } 475 476 static int _origin_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), 477 struct dm_report_field *field, 478 const void *data, void *private __attribute((unused))) 479 { 480 const struct logical_volume *lv = (const struct logical_volume *) data; 481 482 if (lv_is_cow(lv)) 483 return dm_report_field_string(rh, field, 484 (const char **) &origin_from_cow(lv)->name); 485 486 dm_report_field_set_value(field, "", NULL); 487 return 1; 488 } 489 490 static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), 491 struct dm_report_field *field, 492 const void *data, void *private __attribute((unused))) 493 { 494 const struct logical_volume *lv = (const struct logical_volume *) data; 495 struct lv_segment *seg; 496 497 dm_list_iterate_items(seg, &lv->segments) { 498 if (!seg_is_mirrored(seg) || !seg->log_lv) 499 continue; 500 return dm_report_field_string(rh, field, 501 (const char **) &seg->log_lv->name); 502 } 503 504 dm_report_field_set_value(field, "", NULL); 505 return 1; 506 } 507 508 static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem, 509 struct dm_report_field *field, 510 const void *data, void *private __attribute((unused))) 511 { 512 const struct logical_volume *lv = (const struct logical_volume *) data; 513 char *repstr, *lvname; 514 size_t len; 515 516 if (lv_is_displayable(lv)) { 517 repstr = lv->name; 518 return dm_report_field_string(rh, field, (const char **) &repstr); 519 } 520 521 len = strlen(lv->name) + 3; 522 if (!(repstr = dm_pool_zalloc(mem, len))) { 523 log_error("dm_pool_alloc failed"); 524 return 0; 525 } 526 527 if (dm_snprintf(repstr, len, "[%s]", lv->name) < 0) { 528 log_error("lvname snprintf failed"); 529 return 0; 530 } 531 532 if (!(lvname = dm_pool_strdup(mem, lv->name))) { 533 log_error("dm_pool_strdup failed"); 534 return 0; 535 } 536 537 dm_report_field_set_value(field, repstr, lvname); 538 539 return 1; 540 } 541 542 static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), 543 struct dm_report_field *field, 544 const void *data, void *private __attribute((unused))) 545 { 546 const struct logical_volume *lv = (const struct logical_volume *) data; 547 const char *name; 548 struct lv_segment *seg; 549 550 dm_list_iterate_items(seg, &lv->segments) { 551 if (!(seg->status & PVMOVE)) 552 continue; 553 name = dev_name(seg_dev(seg, 0)); 554 return dm_report_field_string(rh, field, &name); 555 } 556 557 dm_report_field_set_value(field, "", NULL); 558 return 1; 559 } 560 561 static int _convertlv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), 562 struct dm_report_field *field, 563 const void *data, void *private __attribute((unused))) 564 { 565 const struct logical_volume *lv = (const struct logical_volume *) data; 566 const char *name = NULL; 567 struct lv_segment *seg; 568 569 if (lv->status & CONVERTING) { 570 if (lv->status & MIRRORED) { 571 seg = first_seg(lv); 572 573 /* Temporary mirror is always area_num == 0 */ 574 if (seg_type(seg, 0) == AREA_LV && 575 is_temporary_mirror_layer(seg_lv(seg, 0))) 576 name = seg_lv(seg, 0)->name; 577 } 578 } 579 580 if (name) 581 return dm_report_field_string(rh, field, &name); 582 583 dm_report_field_set_value(field, "", NULL); 584 return 1; 585 } 586 587 static int _size32_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 588 struct dm_report_field *field, 589 const void *data, void *private) 590 { 591 const uint32_t size = *(const uint32_t *) data; 592 const char *disp, *repstr; 593 uint64_t *sortval; 594 595 if (!*(disp = display_size_units(private, (uint64_t) size))) 596 return_0; 597 598 if (!(repstr = dm_pool_strdup(mem, disp))) { 599 log_error("dm_pool_strdup failed"); 600 return 0; 601 } 602 603 if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { 604 log_error("dm_pool_alloc failed"); 605 return 0; 606 } 607 608 *sortval = (const uint64_t) size; 609 610 dm_report_field_set_value(field, repstr, sortval); 611 612 return 1; 613 } 614 615 static int _size64_disp(struct dm_report *rh __attribute((unused)), 616 struct dm_pool *mem, 617 struct dm_report_field *field, 618 const void *data, void *private) 619 { 620 const uint64_t size = *(const uint64_t *) data; 621 const char *disp, *repstr; 622 uint64_t *sortval; 623 624 if (!*(disp = display_size_units(private, size))) 625 return_0; 626 627 if (!(repstr = dm_pool_strdup(mem, disp))) { 628 log_error("dm_pool_strdup failed"); 629 return 0; 630 } 631 632 if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { 633 log_error("dm_pool_alloc failed"); 634 return 0; 635 } 636 637 *sortval = size; 638 dm_report_field_set_value(field, repstr, sortval); 639 640 return 1; 641 } 642 643 static int _lvreadahead_disp(struct dm_report *rh, struct dm_pool *mem, 644 struct dm_report_field *field, 645 const void *data, void *private __attribute((unused))) 646 { 647 const struct logical_volume *lv = (const struct logical_volume *) data; 648 649 if (lv->read_ahead == DM_READ_AHEAD_AUTO) { 650 dm_report_field_set_value(field, "auto", &_minusone); 651 return 1; 652 } 653 654 return _size32_disp(rh, mem, field, &lv->read_ahead, private); 655 } 656 657 static int _lvkreadahead_disp(struct dm_report *rh, struct dm_pool *mem, 658 struct dm_report_field *field, 659 const void *data, 660 void *private) 661 { 662 const struct logical_volume *lv = (const struct logical_volume *) data; 663 struct lvinfo info; 664 665 if (!lv_info(lv->vg->cmd, lv, &info, 0, 1) || !info.exists) 666 return dm_report_field_uint64(rh, field, &_minusone); 667 668 return _size32_disp(rh, mem, field, &info.read_ahead, private); 669 } 670 671 static int _vgsize_disp(struct dm_report *rh, struct dm_pool *mem, 672 struct dm_report_field *field, 673 const void *data, void *private) 674 { 675 const struct volume_group *vg = (const struct volume_group *) data; 676 uint64_t size; 677 678 size = (uint64_t) vg->extent_count * vg->extent_size; 679 680 return _size64_disp(rh, mem, field, &size, private); 681 } 682 683 static int _segstart_disp(struct dm_report *rh, struct dm_pool *mem, 684 struct dm_report_field *field, 685 const void *data, void *private) 686 { 687 const struct lv_segment *seg = (const struct lv_segment *) data; 688 uint64_t start; 689 690 start = (uint64_t) seg->le * seg->lv->vg->extent_size; 691 692 return _size64_disp(rh, mem, field, &start, private); 693 } 694 695 static int _segstartpe_disp(struct dm_report *rh, 696 struct dm_pool *mem __attribute((unused)), 697 struct dm_report_field *field, 698 const void *data, 699 void *private __attribute((unused))) 700 { 701 const struct lv_segment *seg = (const struct lv_segment *) data; 702 703 return dm_report_field_uint32(rh, field, &seg->le); 704 } 705 706 static int _segsize_disp(struct dm_report *rh, struct dm_pool *mem, 707 struct dm_report_field *field, 708 const void *data, void *private) 709 { 710 const struct lv_segment *seg = (const struct lv_segment *) data; 711 uint64_t size; 712 713 size = (uint64_t) seg->len * seg->lv->vg->extent_size; 714 715 return _size64_disp(rh, mem, field, &size, private); 716 } 717 718 static int _chunksize_disp(struct dm_report *rh, struct dm_pool *mem, 719 struct dm_report_field *field, 720 const void *data, void *private) 721 { 722 const struct lv_segment *seg = (const struct lv_segment *) data; 723 uint64_t size; 724 725 if (lv_is_cow(seg->lv)) 726 size = (uint64_t) find_cow(seg->lv)->chunk_size; 727 else 728 size = 0; 729 730 return _size64_disp(rh, mem, field, &size, private); 731 } 732 733 static int _pvused_disp(struct dm_report *rh, struct dm_pool *mem, 734 struct dm_report_field *field, 735 const void *data, void *private) 736 { 737 const struct physical_volume *pv = 738 (const struct physical_volume *) data; 739 uint64_t used; 740 741 if (!pv->pe_count) 742 used = 0LL; 743 else 744 used = (uint64_t) pv->pe_alloc_count * pv->pe_size; 745 746 return _size64_disp(rh, mem, field, &used, private); 747 } 748 749 static int _pvfree_disp(struct dm_report *rh, struct dm_pool *mem, 750 struct dm_report_field *field, 751 const void *data, void *private) 752 { 753 const struct physical_volume *pv = 754 (const struct physical_volume *) data; 755 uint64_t freespace; 756 757 if (!pv->pe_count) 758 freespace = pv->size; 759 else 760 freespace = (uint64_t) (pv->pe_count - pv->pe_alloc_count) * pv->pe_size; 761 762 return _size64_disp(rh, mem, field, &freespace, private); 763 } 764 765 static int _pvsize_disp(struct dm_report *rh, struct dm_pool *mem, 766 struct dm_report_field *field, 767 const void *data, void *private) 768 { 769 const struct physical_volume *pv = 770 (const struct physical_volume *) data; 771 uint64_t size; 772 773 if (!pv->pe_count) 774 size = pv->size; 775 else 776 size = (uint64_t) pv->pe_count * pv->pe_size; 777 778 return _size64_disp(rh, mem, field, &size, private); 779 } 780 781 static int _devsize_disp(struct dm_report *rh, struct dm_pool *mem, 782 struct dm_report_field *field, 783 const void *data, void *private) 784 { 785 const struct device *dev = *(const struct device **) data; 786 uint64_t size; 787 788 if (!dev_get_size(dev, &size)) 789 size = 0; 790 791 return _size64_disp(rh, mem, field, &size, private); 792 } 793 794 static int _vgfree_disp(struct dm_report *rh, struct dm_pool *mem, 795 struct dm_report_field *field, 796 const void *data, void *private) 797 { 798 const struct volume_group *vg = (const struct volume_group *) data; 799 uint64_t freespace; 800 801 freespace = (uint64_t) vg->free_count * vg->extent_size; 802 803 return _size64_disp(rh, mem, field, &freespace, private); 804 } 805 806 static int _uuid_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 807 struct dm_report_field *field, 808 const void *data, void *private __attribute((unused))) 809 { 810 char *repstr = NULL; 811 812 if (!(repstr = dm_pool_alloc(mem, 40))) { 813 log_error("dm_pool_alloc failed"); 814 return 0; 815 } 816 817 if (!id_write_format((const struct id *) data, repstr, 40)) 818 return_0; 819 820 dm_report_field_set_value(field, repstr, NULL); 821 return 1; 822 } 823 824 static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), 825 struct dm_report_field *field, 826 const void *data, void *private __attribute((unused))) 827 { 828 return dm_report_field_uint32(rh, field, data); 829 } 830 831 static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), 832 struct dm_report_field *field, 833 const void *data, void *private __attribute((unused))) 834 { 835 return dm_report_field_int32(rh, field, data); 836 } 837 838 static int _pvmdas_disp(struct dm_report *rh, struct dm_pool *mem, 839 struct dm_report_field *field, 840 const void *data, void *private) 841 { 842 struct lvmcache_info *info; 843 uint32_t count; 844 const char *pvid = (const char *)(&((struct id *) data)->uuid); 845 846 info = info_from_pvid(pvid, 0); 847 count = info ? dm_list_size(&info->mdas) : 0; 848 849 return _uint32_disp(rh, mem, field, &count, private); 850 } 851 852 static int _vgmdas_disp(struct dm_report *rh, struct dm_pool *mem, 853 struct dm_report_field *field, 854 const void *data, void *private) 855 { 856 const struct volume_group *vg = (const struct volume_group *) data; 857 uint32_t count; 858 859 count = dm_list_size(&vg->fid->metadata_areas); 860 861 return _uint32_disp(rh, mem, field, &count, private); 862 } 863 864 static int _pvmdafree_disp(struct dm_report *rh, struct dm_pool *mem, 865 struct dm_report_field *field, 866 const void *data, void *private) 867 { 868 struct lvmcache_info *info; 869 uint64_t freespace = UINT64_MAX, mda_free; 870 const char *pvid = (const char *)(&((struct id *) data)->uuid); 871 struct metadata_area *mda; 872 873 info = info_from_pvid(pvid, 0); 874 875 dm_list_iterate_items(mda, &info->mdas) { 876 if (!mda->ops->mda_free_sectors) 877 continue; 878 mda_free = mda->ops->mda_free_sectors(mda); 879 if (mda_free < freespace) 880 freespace = mda_free; 881 } 882 883 if (freespace == UINT64_MAX) 884 freespace = UINT64_C(0); 885 886 return _size64_disp(rh, mem, field, &freespace, private); 887 } 888 889 static uint64_t _find_min_mda_size(struct dm_list *mdas) 890 { 891 uint64_t min_mda_size = UINT64_MAX, mda_size; 892 struct metadata_area *mda; 893 894 dm_list_iterate_items(mda, mdas) { 895 if (!mda->ops->mda_total_sectors) 896 continue; 897 mda_size = mda->ops->mda_total_sectors(mda); 898 if (mda_size < min_mda_size) 899 min_mda_size = mda_size; 900 } 901 902 if (min_mda_size == UINT64_MAX) 903 min_mda_size = UINT64_C(0); 904 905 return min_mda_size; 906 } 907 908 static int _pvmdasize_disp(struct dm_report *rh, struct dm_pool *mem, 909 struct dm_report_field *field, 910 const void *data, void *private) 911 { 912 struct lvmcache_info *info; 913 uint64_t min_mda_size; 914 const char *pvid = (const char *)(&((struct id *) data)->uuid); 915 916 info = info_from_pvid(pvid, 0); 917 918 /* PVs could have 2 mdas of different sizes (rounding effect) */ 919 min_mda_size = _find_min_mda_size(&info->mdas); 920 921 return _size64_disp(rh, mem, field, &min_mda_size, private); 922 } 923 924 static int _vgmdasize_disp(struct dm_report *rh, struct dm_pool *mem, 925 struct dm_report_field *field, 926 const void *data, void *private) 927 { 928 const struct volume_group *vg = (const struct volume_group *) data; 929 uint64_t min_mda_size; 930 931 min_mda_size = _find_min_mda_size(&vg->fid->metadata_areas); 932 933 return _size64_disp(rh, mem, field, &min_mda_size, private); 934 } 935 936 static int _vgmdafree_disp(struct dm_report *rh, struct dm_pool *mem, 937 struct dm_report_field *field, 938 const void *data, void *private) 939 { 940 const struct volume_group *vg = (const struct volume_group *) data; 941 uint64_t freespace = UINT64_MAX, mda_free; 942 struct metadata_area *mda; 943 944 dm_list_iterate_items(mda, &vg->fid->metadata_areas) { 945 if (!mda->ops->mda_free_sectors) 946 continue; 947 mda_free = mda->ops->mda_free_sectors(mda); 948 if (mda_free < freespace) 949 freespace = mda_free; 950 } 951 952 if (freespace == UINT64_MAX) 953 freespace = UINT64_C(0); 954 955 return _size64_disp(rh, mem, field, &freespace, private); 956 } 957 958 static int _lvcount_disp(struct dm_report *rh, struct dm_pool *mem, 959 struct dm_report_field *field, 960 const void *data, void *private) 961 { 962 const struct volume_group *vg = (const struct volume_group *) data; 963 uint32_t count; 964 965 count = displayable_lvs_in_vg(vg); 966 967 return _uint32_disp(rh, mem, field, &count, private); 968 } 969 970 static int _lvsegcount_disp(struct dm_report *rh, struct dm_pool *mem, 971 struct dm_report_field *field, 972 const void *data, void *private) 973 { 974 const struct logical_volume *lv = (const struct logical_volume *) data; 975 uint32_t count; 976 977 count = dm_list_size(&lv->segments); 978 979 return _uint32_disp(rh, mem, field, &count, private); 980 } 981 982 static int _snpercent_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 983 struct dm_report_field *field, 984 const void *data, void *private __attribute((unused))) 985 { 986 const struct logical_volume *lv = (const struct logical_volume *) data; 987 struct lvinfo info; 988 float snap_percent; 989 uint64_t *sortval; 990 char *repstr; 991 992 /* Suppress snapshot percentage if not using driver */ 993 if (!activation()) { 994 dm_report_field_set_value(field, "", NULL); 995 return 1; 996 } 997 998 if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { 999 log_error("dm_pool_alloc failed"); 1000 return 0; 1001 } 1002 1003 if (!lv_is_cow(lv) || 1004 (lv_info(lv->vg->cmd, lv, &info, 0, 0) && !info.exists)) { 1005 *sortval = UINT64_C(0); 1006 dm_report_field_set_value(field, "", sortval); 1007 return 1; 1008 } 1009 1010 if (!lv_snapshot_percent(lv, &snap_percent) || snap_percent < 0) { 1011 *sortval = UINT64_C(100); 1012 dm_report_field_set_value(field, "100.00", sortval); 1013 return 1; 1014 } 1015 1016 if (!(repstr = dm_pool_zalloc(mem, 8))) { 1017 log_error("dm_pool_alloc failed"); 1018 return 0; 1019 } 1020 1021 if (dm_snprintf(repstr, 7, "%.2f", snap_percent) < 0) { 1022 log_error("snapshot percentage too large"); 1023 return 0; 1024 } 1025 1026 *sortval = snap_percent * UINT64_C(1000); 1027 dm_report_field_set_value(field, repstr, sortval); 1028 1029 return 1; 1030 } 1031 1032 static int _copypercent_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 1033 struct dm_report_field *field, 1034 const void *data, void *private __attribute((unused))) 1035 { 1036 struct logical_volume *lv = (struct logical_volume *) data; 1037 float percent; 1038 uint64_t *sortval; 1039 char *repstr; 1040 1041 if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { 1042 log_error("dm_pool_alloc failed"); 1043 return 0; 1044 } 1045 1046 if ((!(lv->status & PVMOVE) && !(lv->status & MIRRORED)) || 1047 !lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, NULL)) { 1048 *sortval = UINT64_C(0); 1049 dm_report_field_set_value(field, "", sortval); 1050 return 1; 1051 } 1052 1053 percent = copy_percent(lv); 1054 1055 if (!(repstr = dm_pool_zalloc(mem, 8))) { 1056 log_error("dm_pool_alloc failed"); 1057 return 0; 1058 } 1059 1060 if (dm_snprintf(repstr, 7, "%.2f", percent) < 0) { 1061 log_error("copy percentage too large"); 1062 return 0; 1063 } 1064 1065 *sortval = percent * UINT64_C(1000); 1066 dm_report_field_set_value(field, repstr, sortval); 1067 1068 return 1; 1069 } 1070 1071 /* Report object types */ 1072 1073 /* necessary for displaying something for PVs not belonging to VG */ 1074 static struct format_instance _dummy_fid = { 1075 .metadata_areas = { &(_dummy_fid.metadata_areas), &(_dummy_fid.metadata_areas) }, 1076 }; 1077 1078 static struct volume_group _dummy_vg = { 1079 .fid = &_dummy_fid, 1080 .name = (char *) "", 1081 .system_id = (char *) "", 1082 .pvs = { &(_dummy_vg.pvs), &(_dummy_vg.pvs) }, 1083 .lvs = { &(_dummy_vg.lvs), &(_dummy_vg.lvs) }, 1084 .tags = { &(_dummy_vg.tags), &(_dummy_vg.tags) }, 1085 }; 1086 1087 static void *_obj_get_vg(void *obj) 1088 { 1089 struct volume_group *vg = ((struct lvm_report_object *)obj)->vg; 1090 1091 return vg ? vg : &_dummy_vg; 1092 } 1093 1094 static void *_obj_get_lv(void *obj) 1095 { 1096 return ((struct lvm_report_object *)obj)->lv; 1097 } 1098 1099 static void *_obj_get_pv(void *obj) 1100 { 1101 return ((struct lvm_report_object *)obj)->pv; 1102 } 1103 1104 static void *_obj_get_seg(void *obj) 1105 { 1106 return ((struct lvm_report_object *)obj)->seg; 1107 } 1108 1109 static void *_obj_get_pvseg(void *obj) 1110 { 1111 return ((struct lvm_report_object *)obj)->pvseg; 1112 } 1113 1114 static const struct dm_report_object_type _report_types[] = { 1115 { VGS, "Volume Group", "vg_", _obj_get_vg }, 1116 { LVS, "Logical Volume", "lv_", _obj_get_lv }, 1117 { PVS, "Physical Volume", "pv_", _obj_get_pv }, 1118 { SEGS, "Logical Volume Segment", "seg_", _obj_get_seg }, 1119 { PVSEGS, "Physical Volume Segment", "pvseg_", _obj_get_pvseg }, 1120 { 0, "", "", NULL }, 1121 }; 1122 1123 /* 1124 * Import column definitions 1125 */ 1126 1127 #define STR DM_REPORT_FIELD_TYPE_STRING 1128 #define NUM DM_REPORT_FIELD_TYPE_NUMBER 1129 #define FIELD(type, strct, sorttype, head, field, width, func, id, desc) {type, sorttype, (off_t)((uintptr_t)&_dummy._ ## strct.field - (uintptr_t)&_dummy._ ## strct), width, id, head, &_ ## func ## _disp, desc}, 1130 1131 static struct dm_report_field_type _fields[] = { 1132 #include "columns.h" 1133 {0, 0, 0, 0, "", "", NULL, NULL}, 1134 }; 1135 1136 #undef STR 1137 #undef NUM 1138 #undef FIELD 1139 1140 void *report_init(struct cmd_context *cmd, const char *format, const char *keys, 1141 report_type_t *report_type, const char *separator, 1142 int aligned, int buffered, int headings, int field_prefixes, 1143 int quoted, int columns_as_rows) 1144 { 1145 uint32_t report_flags = 0; 1146 void *rh; 1147 1148 if (aligned) 1149 report_flags |= DM_REPORT_OUTPUT_ALIGNED; 1150 1151 if (buffered) 1152 report_flags |= DM_REPORT_OUTPUT_BUFFERED; 1153 1154 if (headings) 1155 report_flags |= DM_REPORT_OUTPUT_HEADINGS; 1156 1157 if (field_prefixes) 1158 report_flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX; 1159 1160 if (!quoted) 1161 report_flags |= DM_REPORT_OUTPUT_FIELD_UNQUOTED; 1162 1163 if (columns_as_rows) 1164 report_flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS; 1165 1166 rh = dm_report_init(report_type, _report_types, _fields, format, 1167 separator, report_flags, keys, cmd); 1168 1169 if (rh && field_prefixes) 1170 dm_report_set_output_field_name_prefix(rh, "lvm2_"); 1171 1172 return rh; 1173 } 1174 1175 /* 1176 * Create a row of data for an object 1177 */ 1178 int report_object(void *handle, struct volume_group *vg, 1179 struct logical_volume *lv, struct physical_volume *pv, 1180 struct lv_segment *seg, struct pv_segment *pvseg) 1181 { 1182 struct lvm_report_object obj; 1183 1184 /* The two format fields might as well match. */ 1185 if (!vg && pv) 1186 _dummy_fid.fmt = pv->fmt; 1187 1188 obj.vg = vg; 1189 obj.lv = lv; 1190 obj.pv = pv; 1191 obj.seg = seg; 1192 obj.pvseg = pvseg; 1193 1194 return dm_report_object(handle, &obj); 1195 } 1196