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