1 /* $NetBSD: report.c,v 1.1.1.3 2009/12/02 00:26:46 haad Exp $ */ 2 3 /* 4 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved. 5 * Copyright (C) 2004-2009 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 percent_range_t percent_range; 281 struct lv_segment *mirror_seg = find_mirror_seg(first_seg(lv)); 282 283 if (!(lv->status & MIRROR_IMAGE) || !mirror_seg) 284 return_0; 285 286 if (!lv_mirror_percent(lv->vg->cmd, mirror_seg->lv, 0, &percent, 287 &percent_range, NULL)) 288 return_0; 289 290 return (percent_range == PERCENT_100) ? 1 : 0; 291 } 292 293 static int _lvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 294 struct dm_report_field *field, 295 const void *data, void *private __attribute((unused))) 296 { 297 const struct logical_volume *lv = (const struct logical_volume *) data; 298 struct lvinfo info; 299 char *repstr; 300 float snap_percent; 301 percent_range_t percent_range; 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 & VIRTUAL) 317 repstr[0] = 'v'; 318 /* Origin takes precedence over Mirror */ 319 else if (lv_is_origin(lv)) 320 repstr[0] = 'o'; 321 else if (lv->status & MIRRORED) { 322 if (lv->status & MIRROR_NOTSYNCED) 323 repstr[0] = 'M'; 324 else 325 repstr[0] = 'm'; 326 }else if (lv->status & MIRROR_IMAGE) 327 if (_lv_mimage_in_sync(lv)) 328 repstr[0] = 'i'; 329 else 330 repstr[0] = 'I'; 331 else if (lv->status & MIRROR_LOG) 332 repstr[0] = 'l'; 333 else if (lv_is_cow(lv)) 334 repstr[0] = 's'; 335 else 336 repstr[0] = '-'; 337 338 if (lv->status & PVMOVE) 339 repstr[1] = '-'; 340 else if (lv->status & LVM_WRITE) 341 repstr[1] = 'w'; 342 else if (lv->status & LVM_READ) 343 repstr[1] = 'r'; 344 else 345 repstr[1] = '-'; 346 347 repstr[2] = _alloc_policy_char(lv->alloc); 348 349 if (lv->status & LOCKED) 350 repstr[2] = toupper(repstr[2]); 351 352 if (lv->status & FIXED_MINOR) 353 repstr[3] = 'm'; /* Fixed Minor */ 354 else 355 repstr[3] = '-'; 356 357 if (lv_info(lv->vg->cmd, lv, &info, 1, 0) && info.exists) { 358 if (info.suspended) 359 repstr[4] = 's'; /* Suspended */ 360 else if (info.live_table) 361 repstr[4] = 'a'; /* Active */ 362 else if (info.inactive_table) 363 repstr[4] = 'i'; /* Inactive with table */ 364 else 365 repstr[4] = 'd'; /* Inactive without table */ 366 367 /* Snapshot dropped? */ 368 if (info.live_table && lv_is_cow(lv) && 369 (!lv_snapshot_percent(lv, &snap_percent, &percent_range) || 370 percent_range == PERCENT_INVALID)) { 371 repstr[0] = toupper(repstr[0]); 372 if (info.suspended) 373 repstr[4] = 'S'; /* Susp Inv snapshot */ 374 else 375 repstr[4] = 'I'; /* Invalid snapshot */ 376 } 377 378 if (info.open_count) 379 repstr[5] = 'o'; /* Open */ 380 else 381 repstr[5] = '-'; 382 } else { 383 repstr[4] = '-'; 384 repstr[5] = '-'; 385 } 386 387 out: 388 dm_report_field_set_value(field, repstr, NULL); 389 return 1; 390 } 391 392 static int _pvstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 393 struct dm_report_field *field, 394 const void *data, void *private __attribute((unused))) 395 { 396 const uint32_t status = *(const uint32_t *) data; 397 char *repstr; 398 399 if (!(repstr = dm_pool_zalloc(mem, 3))) { 400 log_error("dm_pool_alloc failed"); 401 return 0; 402 } 403 404 if (status & ALLOCATABLE_PV) 405 repstr[0] = 'a'; 406 else 407 repstr[0] = '-'; 408 409 if (status & EXPORTED_VG) 410 repstr[1] = 'x'; 411 else 412 repstr[1] = '-'; 413 414 dm_report_field_set_value(field, repstr, NULL); 415 return 1; 416 } 417 418 static int _vgstatus_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 419 struct dm_report_field *field, 420 const void *data, void *private __attribute((unused))) 421 { 422 const struct volume_group *vg = (const struct volume_group *) data; 423 char *repstr; 424 425 if (!(repstr = dm_pool_zalloc(mem, 7))) { 426 log_error("dm_pool_alloc failed"); 427 return 0; 428 } 429 430 if (vg->status & LVM_WRITE) 431 repstr[0] = 'w'; 432 else 433 repstr[0] = 'r'; 434 435 if (vg_is_resizeable(vg)) 436 repstr[1] = 'z'; 437 else 438 repstr[1] = '-'; 439 440 if (vg_is_exported(vg)) 441 repstr[2] = 'x'; 442 else 443 repstr[2] = '-'; 444 445 if (vg_missing_pv_count(vg)) 446 repstr[3] = 'p'; 447 else 448 repstr[3] = '-'; 449 450 repstr[4] = _alloc_policy_char(vg->alloc); 451 452 if (vg_is_clustered(vg)) 453 repstr[5] = 'c'; 454 else 455 repstr[5] = '-'; 456 457 dm_report_field_set_value(field, repstr, NULL); 458 return 1; 459 } 460 461 static int _segtype_disp(struct dm_report *rh __attribute((unused)), 462 struct dm_pool *mem __attribute((unused)), 463 struct dm_report_field *field, 464 const void *data, void *private __attribute((unused))) 465 { 466 const struct lv_segment *seg = (const struct lv_segment *) data; 467 468 if (seg->area_count == 1) { 469 dm_report_field_set_value(field, "linear", NULL); 470 return 1; 471 } 472 473 dm_report_field_set_value(field, seg->segtype->ops->name(seg), NULL); 474 return 1; 475 } 476 477 static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), 478 struct dm_report_field *field, 479 const void *data, void *private __attribute((unused))) 480 { 481 const struct logical_volume *lv = (const struct logical_volume *) data; 482 struct lv_segment *seg; 483 484 dm_list_iterate_items(seg, &lv->segments) { 485 if (!seg_is_mirrored(seg) || !seg->log_lv) 486 continue; 487 return dm_report_field_string(rh, field, 488 (const char **) &seg->log_lv->name); 489 } 490 491 dm_report_field_set_value(field, "", NULL); 492 return 1; 493 } 494 495 static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem, 496 struct dm_report_field *field, 497 const void *data, void *private __attribute((unused))) 498 { 499 const struct logical_volume *lv = (const struct logical_volume *) data; 500 char *repstr, *lvname; 501 size_t len; 502 503 if (lv_is_visible(lv)) { 504 repstr = lv->name; 505 return dm_report_field_string(rh, field, (const char **) &repstr); 506 } 507 508 len = strlen(lv->name) + 3; 509 if (!(repstr = dm_pool_zalloc(mem, len))) { 510 log_error("dm_pool_alloc failed"); 511 return 0; 512 } 513 514 if (dm_snprintf(repstr, len, "[%s]", lv->name) < 0) { 515 log_error("lvname snprintf failed"); 516 return 0; 517 } 518 519 if (!(lvname = dm_pool_strdup(mem, lv->name))) { 520 log_error("dm_pool_strdup failed"); 521 return 0; 522 } 523 524 dm_report_field_set_value(field, repstr, lvname); 525 526 return 1; 527 } 528 529 static int _origin_disp(struct dm_report *rh, struct dm_pool *mem, 530 struct dm_report_field *field, 531 const void *data, void *private) 532 { 533 const struct logical_volume *lv = (const struct logical_volume *) data; 534 535 if (lv_is_cow(lv)) 536 return _lvname_disp(rh, mem, field, origin_from_cow(lv), private); 537 538 dm_report_field_set_value(field, "", NULL); 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_size(vg); 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 = UINT64_C(0); 729 730 return _size64_disp(rh, mem, field, &size, private); 731 } 732 733 static int _originsize_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 logical_volume *lv = (const struct logical_volume *) data; 738 uint64_t size; 739 740 if (lv_is_cow(lv)) 741 size = (uint64_t) find_cow(lv)->len * lv->vg->extent_size; 742 else if (lv_is_origin(lv)) 743 size = lv->size; 744 else 745 size = UINT64_C(0); 746 747 return _size64_disp(rh, mem, field, &size, private); 748 } 749 750 static int _pvused_disp(struct dm_report *rh, struct dm_pool *mem, 751 struct dm_report_field *field, 752 const void *data, void *private) 753 { 754 const struct physical_volume *pv = 755 (const struct physical_volume *) data; 756 uint64_t used; 757 758 if (!pv->pe_count) 759 used = 0LL; 760 else 761 used = (uint64_t) pv->pe_alloc_count * pv->pe_size; 762 763 return _size64_disp(rh, mem, field, &used, private); 764 } 765 766 static int _pvfree_disp(struct dm_report *rh, struct dm_pool *mem, 767 struct dm_report_field *field, 768 const void *data, void *private) 769 { 770 const struct physical_volume *pv = 771 (const struct physical_volume *) data; 772 uint64_t freespace; 773 774 if (!pv->pe_count) 775 freespace = pv->size; 776 else 777 freespace = (uint64_t) (pv->pe_count - pv->pe_alloc_count) * pv->pe_size; 778 779 return _size64_disp(rh, mem, field, &freespace, private); 780 } 781 782 static int _pvsize_disp(struct dm_report *rh, struct dm_pool *mem, 783 struct dm_report_field *field, 784 const void *data, void *private) 785 { 786 const struct physical_volume *pv = 787 (const struct physical_volume *) data; 788 uint64_t size; 789 790 if (!pv->pe_count) 791 size = pv->size; 792 else 793 size = (uint64_t) pv->pe_count * pv->pe_size; 794 795 return _size64_disp(rh, mem, field, &size, private); 796 } 797 798 static int _devsize_disp(struct dm_report *rh, struct dm_pool *mem, 799 struct dm_report_field *field, 800 const void *data, void *private) 801 { 802 const struct device *dev = *(const struct device **) data; 803 uint64_t size; 804 805 if (!dev_get_size(dev, &size)) 806 size = 0; 807 808 return _size64_disp(rh, mem, field, &size, private); 809 } 810 811 static int _vgfree_disp(struct dm_report *rh, struct dm_pool *mem, 812 struct dm_report_field *field, 813 const void *data, void *private) 814 { 815 const struct volume_group *vg = (const struct volume_group *) data; 816 uint64_t freespace; 817 818 freespace = (uint64_t) vg_free(vg); 819 820 return _size64_disp(rh, mem, field, &freespace, private); 821 } 822 823 static int _uuid_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 824 struct dm_report_field *field, 825 const void *data, void *private __attribute((unused))) 826 { 827 char *repstr = NULL; 828 829 if (!(repstr = dm_pool_alloc(mem, 40))) { 830 log_error("dm_pool_alloc failed"); 831 return 0; 832 } 833 834 if (!id_write_format((const struct id *) data, repstr, 40)) 835 return_0; 836 837 dm_report_field_set_value(field, repstr, NULL); 838 return 1; 839 } 840 841 static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), 842 struct dm_report_field *field, 843 const void *data, void *private __attribute((unused))) 844 { 845 return dm_report_field_uint32(rh, field, data); 846 } 847 848 static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute((unused)), 849 struct dm_report_field *field, 850 const void *data, void *private __attribute((unused))) 851 { 852 return dm_report_field_int32(rh, field, data); 853 } 854 855 static int _pvmdas_disp(struct dm_report *rh, struct dm_pool *mem, 856 struct dm_report_field *field, 857 const void *data, void *private) 858 { 859 uint32_t count; 860 const struct physical_volume *pv = 861 (const struct physical_volume *) data; 862 863 count = pv_mda_count(pv); 864 865 return _uint32_disp(rh, mem, field, &count, private); 866 } 867 868 static int _vgmdas_disp(struct dm_report *rh, struct dm_pool *mem, 869 struct dm_report_field *field, 870 const void *data, void *private) 871 { 872 const struct volume_group *vg = (const struct volume_group *) data; 873 uint32_t count; 874 875 count = vg_mda_count(vg); 876 877 return _uint32_disp(rh, mem, field, &count, private); 878 } 879 880 static int _pvmdafree_disp(struct dm_report *rh, struct dm_pool *mem, 881 struct dm_report_field *field, 882 const void *data, void *private) 883 { 884 struct lvmcache_info *info; 885 uint64_t freespace = UINT64_MAX, mda_free; 886 const char *pvid = (const char *)(&((struct id *) data)->uuid); 887 struct metadata_area *mda; 888 889 if ((info = info_from_pvid(pvid, 0))) 890 dm_list_iterate_items(mda, &info->mdas) { 891 if (!mda->ops->mda_free_sectors) 892 continue; 893 mda_free = mda->ops->mda_free_sectors(mda); 894 if (mda_free < freespace) 895 freespace = mda_free; 896 } 897 898 if (freespace == UINT64_MAX) 899 freespace = UINT64_C(0); 900 901 return _size64_disp(rh, mem, field, &freespace, private); 902 } 903 904 static uint64_t _find_min_mda_size(struct dm_list *mdas) 905 { 906 uint64_t min_mda_size = UINT64_MAX, mda_size; 907 struct metadata_area *mda; 908 909 dm_list_iterate_items(mda, mdas) { 910 if (!mda->ops->mda_total_sectors) 911 continue; 912 mda_size = mda->ops->mda_total_sectors(mda); 913 if (mda_size < min_mda_size) 914 min_mda_size = mda_size; 915 } 916 917 if (min_mda_size == UINT64_MAX) 918 min_mda_size = UINT64_C(0); 919 920 return min_mda_size; 921 } 922 923 static int _pvmdasize_disp(struct dm_report *rh, struct dm_pool *mem, 924 struct dm_report_field *field, 925 const void *data, void *private) 926 { 927 struct lvmcache_info *info; 928 uint64_t min_mda_size = 0; 929 const char *pvid = (const char *)(&((struct id *) data)->uuid); 930 931 /* PVs could have 2 mdas of different sizes (rounding effect) */ 932 if ((info = info_from_pvid(pvid, 0))) 933 min_mda_size = _find_min_mda_size(&info->mdas); 934 935 return _size64_disp(rh, mem, field, &min_mda_size, private); 936 } 937 938 static int _vgmdasize_disp(struct dm_report *rh, struct dm_pool *mem, 939 struct dm_report_field *field, 940 const void *data, void *private) 941 { 942 const struct volume_group *vg = (const struct volume_group *) data; 943 uint64_t min_mda_size; 944 945 min_mda_size = _find_min_mda_size(&vg->fid->metadata_areas); 946 947 return _size64_disp(rh, mem, field, &min_mda_size, private); 948 } 949 950 static int _vgmdafree_disp(struct dm_report *rh, struct dm_pool *mem, 951 struct dm_report_field *field, 952 const void *data, void *private) 953 { 954 const struct volume_group *vg = (const struct volume_group *) data; 955 uint64_t freespace = UINT64_MAX, mda_free; 956 struct metadata_area *mda; 957 958 dm_list_iterate_items(mda, &vg->fid->metadata_areas) { 959 if (!mda->ops->mda_free_sectors) 960 continue; 961 mda_free = mda->ops->mda_free_sectors(mda); 962 if (mda_free < freespace) 963 freespace = mda_free; 964 } 965 966 if (freespace == UINT64_MAX) 967 freespace = UINT64_C(0); 968 969 return _size64_disp(rh, mem, field, &freespace, private); 970 } 971 972 static int _lvcount_disp(struct dm_report *rh, struct dm_pool *mem, 973 struct dm_report_field *field, 974 const void *data, void *private) 975 { 976 const struct volume_group *vg = (const struct volume_group *) data; 977 uint32_t count; 978 979 count = vg_visible_lvs(vg); 980 981 return _uint32_disp(rh, mem, field, &count, private); 982 } 983 984 static int _lvsegcount_disp(struct dm_report *rh, struct dm_pool *mem, 985 struct dm_report_field *field, 986 const void *data, void *private) 987 { 988 const struct logical_volume *lv = (const struct logical_volume *) data; 989 uint32_t count; 990 991 count = dm_list_size(&lv->segments); 992 993 return _uint32_disp(rh, mem, field, &count, private); 994 } 995 996 static int _snapcount_disp(struct dm_report *rh, struct dm_pool *mem, 997 struct dm_report_field *field, 998 const void *data, void *private) 999 { 1000 const struct volume_group *vg = (const struct volume_group *) data; 1001 uint32_t count; 1002 1003 count = snapshot_count(vg); 1004 1005 return _uint32_disp(rh, mem, field, &count, private); 1006 } 1007 1008 static int _snpercent_disp(struct dm_report *rh __attribute((unused)), struct dm_pool *mem, 1009 struct dm_report_field *field, 1010 const void *data, void *private __attribute((unused))) 1011 { 1012 const struct logical_volume *lv = (const struct logical_volume *) data; 1013 struct lvinfo info; 1014 float snap_percent; 1015 percent_range_t percent_range; 1016 uint64_t *sortval; 1017 char *repstr; 1018 1019 /* Suppress snapshot percentage if not using driver */ 1020 if (!activation()) { 1021 dm_report_field_set_value(field, "", NULL); 1022 return 1; 1023 } 1024 1025 if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { 1026 log_error("dm_pool_alloc failed"); 1027 return 0; 1028 } 1029 1030 if (!lv_is_cow(lv) || 1031 (lv_info(lv->vg->cmd, lv, &info, 0, 0) && !info.exists)) { 1032 *sortval = UINT64_C(0); 1033 dm_report_field_set_value(field, "", sortval); 1034 return 1; 1035 } 1036 1037 if (!lv_snapshot_percent(lv, &snap_percent, &percent_range) || 1038 (percent_range == PERCENT_INVALID)) { 1039 *sortval = UINT64_C(100); 1040 dm_report_field_set_value(field, "100.00", sortval); 1041 return 1; 1042 } 1043 1044 if (!(repstr = dm_pool_zalloc(mem, 8))) { 1045 log_error("dm_pool_alloc failed"); 1046 return 0; 1047 } 1048 1049 if (dm_snprintf(repstr, 7, "%.2f", snap_percent) < 0) { 1050 log_error("snapshot percentage too large"); 1051 return 0; 1052 } 1053 1054 *sortval = snap_percent * UINT64_C(1000); 1055 dm_report_field_set_value(field, repstr, sortval); 1056 1057 return 1; 1058 } 1059 1060 static int _copypercent_disp(struct dm_report *rh __attribute((unused)), 1061 struct dm_pool *mem, 1062 struct dm_report_field *field, 1063 const void *data, void *private __attribute((unused))) 1064 { 1065 struct logical_volume *lv = (struct logical_volume *) data; 1066 float percent; 1067 percent_range_t percent_range; 1068 uint64_t *sortval; 1069 char *repstr; 1070 1071 if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) { 1072 log_error("dm_pool_alloc failed"); 1073 return 0; 1074 } 1075 1076 if ((!(lv->status & PVMOVE) && !(lv->status & MIRRORED)) || 1077 !lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, &percent_range, 1078 NULL) || (percent_range == PERCENT_INVALID)) { 1079 *sortval = UINT64_C(0); 1080 dm_report_field_set_value(field, "", sortval); 1081 return 1; 1082 } 1083 1084 percent = copy_percent(lv, &percent_range); 1085 1086 if (!(repstr = dm_pool_zalloc(mem, 8))) { 1087 log_error("dm_pool_alloc failed"); 1088 return 0; 1089 } 1090 1091 if (dm_snprintf(repstr, 7, "%.2f", percent) < 0) { 1092 log_error("copy percentage too large"); 1093 return 0; 1094 } 1095 1096 *sortval = percent * UINT64_C(1000); 1097 dm_report_field_set_value(field, repstr, sortval); 1098 1099 return 1; 1100 } 1101 1102 /* Report object types */ 1103 1104 /* necessary for displaying something for PVs not belonging to VG */ 1105 static struct format_instance _dummy_fid = { 1106 .metadata_areas = { &(_dummy_fid.metadata_areas), &(_dummy_fid.metadata_areas) }, 1107 }; 1108 1109 static struct volume_group _dummy_vg = { 1110 .fid = &_dummy_fid, 1111 .name = (char *) "", 1112 .system_id = (char *) "", 1113 .pvs = { &(_dummy_vg.pvs), &(_dummy_vg.pvs) }, 1114 .lvs = { &(_dummy_vg.lvs), &(_dummy_vg.lvs) }, 1115 .tags = { &(_dummy_vg.tags), &(_dummy_vg.tags) }, 1116 }; 1117 1118 static void *_obj_get_vg(void *obj) 1119 { 1120 struct volume_group *vg = ((struct lvm_report_object *)obj)->vg; 1121 1122 return vg ? vg : &_dummy_vg; 1123 } 1124 1125 static void *_obj_get_lv(void *obj) 1126 { 1127 return ((struct lvm_report_object *)obj)->lv; 1128 } 1129 1130 static void *_obj_get_pv(void *obj) 1131 { 1132 return ((struct lvm_report_object *)obj)->pv; 1133 } 1134 1135 static void *_obj_get_seg(void *obj) 1136 { 1137 return ((struct lvm_report_object *)obj)->seg; 1138 } 1139 1140 static void *_obj_get_pvseg(void *obj) 1141 { 1142 return ((struct lvm_report_object *)obj)->pvseg; 1143 } 1144 1145 static const struct dm_report_object_type _report_types[] = { 1146 { VGS, "Volume Group", "vg_", _obj_get_vg }, 1147 { LVS, "Logical Volume", "lv_", _obj_get_lv }, 1148 { PVS, "Physical Volume", "pv_", _obj_get_pv }, 1149 { LABEL, "Physical Volume Label", "pv_", _obj_get_pv }, 1150 { SEGS, "Logical Volume Segment", "seg_", _obj_get_seg }, 1151 { PVSEGS, "Physical Volume Segment", "pvseg_", _obj_get_pvseg }, 1152 { 0, "", "", NULL }, 1153 }; 1154 1155 /* 1156 * Import column definitions 1157 */ 1158 1159 #define STR DM_REPORT_FIELD_TYPE_STRING 1160 #define NUM DM_REPORT_FIELD_TYPE_NUMBER 1161 #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}, 1162 1163 static struct dm_report_field_type _fields[] = { 1164 #include "columns.h" 1165 {0, 0, 0, 0, "", "", NULL, NULL}, 1166 }; 1167 1168 #undef STR 1169 #undef NUM 1170 #undef FIELD 1171 1172 void *report_init(struct cmd_context *cmd, const char *format, const char *keys, 1173 report_type_t *report_type, const char *separator, 1174 int aligned, int buffered, int headings, int field_prefixes, 1175 int quoted, int columns_as_rows) 1176 { 1177 uint32_t report_flags = 0; 1178 void *rh; 1179 1180 if (aligned) 1181 report_flags |= DM_REPORT_OUTPUT_ALIGNED; 1182 1183 if (buffered) 1184 report_flags |= DM_REPORT_OUTPUT_BUFFERED; 1185 1186 if (headings) 1187 report_flags |= DM_REPORT_OUTPUT_HEADINGS; 1188 1189 if (field_prefixes) 1190 report_flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX; 1191 1192 if (!quoted) 1193 report_flags |= DM_REPORT_OUTPUT_FIELD_UNQUOTED; 1194 1195 if (columns_as_rows) 1196 report_flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS; 1197 1198 rh = dm_report_init(report_type, _report_types, _fields, format, 1199 separator, report_flags, keys, cmd); 1200 1201 if (rh && field_prefixes) 1202 dm_report_set_output_field_name_prefix(rh, "lvm2_"); 1203 1204 return rh; 1205 } 1206 1207 /* 1208 * Create a row of data for an object 1209 */ 1210 int report_object(void *handle, struct volume_group *vg, 1211 struct logical_volume *lv, struct physical_volume *pv, 1212 struct lv_segment *seg, struct pv_segment *pvseg) 1213 { 1214 struct lvm_report_object obj; 1215 1216 /* The two format fields might as well match. */ 1217 if (!vg && pv) 1218 _dummy_fid.fmt = pv->fmt; 1219 1220 obj.vg = vg; 1221 obj.lv = lv; 1222 obj.pv = pv; 1223 obj.seg = seg; 1224 obj.pvseg = pvseg; 1225 1226 return dm_report_object(handle, &obj); 1227 } 1228