1 /* $NetBSD: report.c,v 1.2 2011/05/30 16:03:02 joerg 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
31 struct 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
_alloc_policy_char(alloc_policy_t alloc)39 static 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
55 static const uint64_t _minusone = UINT64_C(-1);
56
57 /*
58 * Data-munging functions to prepare each data type for display and sorting
59 */
_string_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))60 static 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
_dev_name_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))67 static 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
_format_pvsegs(struct dm_pool * mem,struct dm_report_field * field,const void * data,int range_format)76 static 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
_devices_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))151 static 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
_peranges_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))158 static 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
_tags_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))165 static 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
_modules_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)195 static 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
_vgfmt_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)213 static 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
_pvfmt_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)227 static 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
_lvkmaj_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))242 static 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
_lvkmin_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))255 static 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
_lv_mimage_in_sync(const struct logical_volume * lv)268 static 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
_lvstatus_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))284 static 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
378 out:
379 dm_report_field_set_value(field, repstr, NULL);
380 return 1;
381 }
382
_pvstatus_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))383 static 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
_vgstatus_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))409 static 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
_segtype_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))452 static 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
_loglv_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))468 static 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
_lvname_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))486 static 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
_origin_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)520 static 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
_movepv_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))533 static 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
_convertlv_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))552 static 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
_size32_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)578 static 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
_size64_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)606 static 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
_lvreadahead_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))634 static 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
_lvkreadahead_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)648 static 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
_vgsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)662 static 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
_segstart_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)674 static 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
_segstartpe_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))686 static 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
_segsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)697 static 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
_chunksize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)709 static 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
_originsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)724 static 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
_pvused_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)741 static 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
_pvfree_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)757 static 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
_pvsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)773 static 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
_devsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)789 static 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
_vgfree_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)802 static 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
_uuid_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))814 static 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
_uint32_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))832 static 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
_int32_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))839 static 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
_pvmdas_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)846 static 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
_vgmdas_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)859 static 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
_pvmdafree_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)871 static 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
_find_min_mda_size(struct dm_list * mdas)895 static 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
_pvmdasize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)914 static 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
_vgmdasize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)929 static 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
_vgmdafree_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)941 static 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
_lvcount_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)963 static 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
_lvsegcount_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)975 static 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
_snapcount_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)987 static 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
_snpercent_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))999 static 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
_copypercent_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))1051 static 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 */
1096 static struct format_instance _dummy_fid = {
1097 .metadata_areas = { &(_dummy_fid.metadata_areas), &(_dummy_fid.metadata_areas) },
1098 };
1099
1100 static 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
_obj_get_vg(void * obj)1109 static 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
_obj_get_lv(void * obj)1116 static void *_obj_get_lv(void *obj)
1117 {
1118 return ((struct lvm_report_object *)obj)->lv;
1119 }
1120
_obj_get_pv(void * obj)1121 static void *_obj_get_pv(void *obj)
1122 {
1123 return ((struct lvm_report_object *)obj)->pv;
1124 }
1125
_obj_get_seg(void * obj)1126 static void *_obj_get_seg(void *obj)
1127 {
1128 return ((struct lvm_report_object *)obj)->seg;
1129 }
1130
_obj_get_pvseg(void * obj)1131 static void *_obj_get_pvseg(void *obj)
1132 {
1133 return ((struct lvm_report_object *)obj)->pvseg;
1134 }
1135
1136 static 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
1156 typedef struct physical_volume type_pv;
1157 typedef struct logical_volume type_lv;
1158 typedef struct volume_group type_vg;
1159 typedef struct lv_segment type_seg;
1160 typedef struct pv_segment type_pvseg;
1161
1162 static 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
report_init(struct cmd_context * cmd,const char * format,const char * keys,report_type_t * report_type,const char * separator,int aligned,int buffered,int headings,int field_prefixes,int quoted,int columns_as_rows)1171 void *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 */
report_object(void * handle,struct volume_group * vg,struct logical_volume * lv,struct physical_volume * pv,struct lv_segment * seg,struct pv_segment * pvseg)1209 int 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