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