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
_alloc_policy_char(alloc_policy_t alloc)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 */
_string_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_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)))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
_format_pvsegs(struct dm_pool * mem,struct dm_report_field * field,const void * data,int range_format)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
_devices_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_peranges_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_tags_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_modules_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_vgfmt_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_pvfmt_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_lvkmaj_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_lvkmin_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_lv_mimage_in_sync(const struct logical_volume * lv)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
_lvstatus_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_pvstatus_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_vgstatus_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_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)))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
_loglv_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_lvname_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_origin_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_movepv_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_convertlv_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_size32_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_size64_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_lvreadahead_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_lvkreadahead_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_vgsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_segstart_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_segstartpe_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_segsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_chunksize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_originsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_pvused_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_pvfree_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_pvsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_devsize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_vgfree_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_uuid_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_uint32_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_int32_disp(struct dm_report * rh,struct dm_pool * mem __attribute ((unused)),struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_pvmdas_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_vgmdas_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_pvmdafree_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_find_min_mda_size(struct dm_list * mdas)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
_pvmdasize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_vgmdasize_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_vgmdafree_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_lvcount_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_lvsegcount_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_snapcount_disp(struct dm_report * rh,struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private)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
_snpercent_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_copypercent_disp(struct dm_report * rh __attribute ((unused)),struct dm_pool * mem,struct dm_report_field * field,const void * data,void * private __attribute ((unused)))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
_obj_get_vg(void * obj)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
_obj_get_lv(void * obj)1126 static void *_obj_get_lv(void *obj)
1127 {
1128 return ((struct lvm_report_object *)obj)->lv;
1129 }
1130
_obj_get_pv(void * obj)1131 static void *_obj_get_pv(void *obj)
1132 {
1133 return ((struct lvm_report_object *)obj)->pv;
1134 }
1135
_obj_get_seg(void * obj)1136 static void *_obj_get_seg(void *obj)
1137 {
1138 return ((struct lvm_report_object *)obj)->seg;
1139 }
1140
_obj_get_pvseg(void * obj)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
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)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 */
report_object(void * handle,struct volume_group * vg,struct logical_volume * lv,struct physical_volume * pv,struct lv_segment * seg,struct pv_segment * pvseg)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