1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +03:00
lvm2/lib/report/report.c

1308 lines
38 KiB
C
Raw Normal View History

/*
2004-03-30 23:35:44 +04:00
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2.
*
2004-03-30 23:35:44 +04:00
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "metadata.h"
#include "report.h"
#include "toolcontext.h"
#include "lvm-string.h"
#include "display.h"
#include "activate.h"
2004-09-16 22:40:56 +04:00
#include "segtype.h"
#include "lvmcache.h"
#include "device-types.h"
#include <stddef.h> /* offsetof() */
struct lvm_report_object {
struct volume_group *vg;
struct logical_volume *lv;
struct physical_volume *pv;
struct lv_segment *seg;
struct pv_segment *pvseg;
struct label *label;
};
static const uint64_t _hundred64 = UINT64_C(100);
static const uint64_t _minusone64 = UINT64_C(-1);
static const int32_t _minusone32 = INT32_C(-1);
static const uint64_t _zero64 = UINT64_C(0);
static int _field_set_value(struct dm_report_field *field, const void *data, const void *sort)
{
dm_report_field_set_value(field, data, sort);
return 1;
}
static int _field_set_percent(struct dm_report_field *field,
struct dm_pool *mem,
percent_t percent)
{
char *repstr;
uint64_t *sortval;
if (percent == PERCENT_INVALID)
return _field_set_value(field, "", &_minusone64);
if (!(repstr = dm_pool_alloc(mem, 8)) ||
!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
if (repstr)
dm_pool_free(mem, repstr);
log_error("dm_pool_alloc failed.");
return 0;
}
if (dm_snprintf(repstr, 7, "%.2f", percent_to_float(percent)) < 0) {
dm_pool_free(mem, repstr);
log_error("Percentage too large.");
return 0;
}
*sortval = (uint64_t)(percent * 1000.f);
return _field_set_value(field, repstr, sortval);
}
/*
* Data-munging functions to prepare each data type for display and sorting
*/
static int _string_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
return dm_report_field_string(rh, field, (const char * const *) data);
}
static int _chars_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
return dm_report_field_string(rh, field, (const char * const *) &data);
}
static int _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)))
{
const char *name = dev_name(*(const struct device * const *) data);
return dm_report_field_string(rh, field, &name);
}
static int _devices_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
char *str;
if (!(str = lvseg_devices(mem, (const struct lv_segment *) data)))
return_0;
return _field_set_value(field, str, NULL);
}
static int _peranges_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
char *str;
if (!(str = lvseg_seg_pe_ranges(mem, (const struct lv_segment *) data)))
return_0;
return _field_set_value(field, str, NULL);
}
static int _tags_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
2004-03-08 20:19:15 +03:00
{
const struct dm_list *tagsl = (const struct dm_list *) data;
char *tags_str;
2004-03-08 20:19:15 +03:00
if (!(tags_str = tags_format_and_copy(mem, tagsl)))
return_0;
2004-03-08 20:19:15 +03:00
return _field_set_value(field, tags_str, NULL);
2004-03-08 20:19:15 +03:00
}
static int _modules_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
char *modules_str;
if (!(modules_str = lv_modules_dup(mem, lv)))
return_0;
return _field_set_value(field, modules_str, NULL);
}
static int _lvprofile_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
if (lv->profile)
return dm_report_field_string(rh, field, &lv->profile->name);
return _field_set_value(field, "", NULL);
}
static int _vgfmt_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct volume_group *vg = (const struct volume_group *) data;
if (vg->fid)
return _string_disp(rh, mem, field, &vg->fid->fmt->name, private);
return _field_set_value(field, "", NULL);
}
static int _pvfmt_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct label *l =
(const struct label *) data;
if (!l->labeller || !l->labeller->fmt) {
dm_report_field_set_value(field, "", NULL);
return 1;
}
return _string_disp(rh, mem, field, &l->labeller->fmt->name, private);
}
static int _lvkmaj_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
int major;
if ((major = lv_kernel_major(lv)) >= 0)
return dm_report_field_int(rh, field, &major);
return dm_report_field_int32(rh, field, &_minusone32);
}
static int _lvkmin_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
int minor;
if ((minor = lv_kernel_minor(lv)) >= 0)
return dm_report_field_int(rh, field, &minor);
return dm_report_field_int32(rh, field, &_minusone32);
}
static int _lvstatus_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
char *repstr;
if (!(repstr = lv_attr_dup(mem, lv)))
return_0;
return _field_set_value(field, repstr, NULL);
}
static int _pvstatus_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const struct physical_volume *pv =
(const struct physical_volume *) data;
char *repstr;
if (!(repstr = pv_attr_dup(mem, pv)))
return_0;
return _field_set_value(field, repstr, NULL);
}
static int _vgstatus_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const struct volume_group *vg = (const struct volume_group *) data;
char *repstr;
if (!(repstr = vg_attr_dup(mem, vg)))
return_0;
2005-08-16 03:34:11 +04:00
return _field_set_value(field, repstr, NULL);
}
static int _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)))
{
const struct lv_segment *seg = (const struct lv_segment *) data;
char *name;
if (!(name = lvseg_segtype_dup(mem, seg))) {
log_error("Failed to get segtype.");
return 0;
}
return _field_set_value(field, name, NULL);
}
static int _loglv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
2005-06-01 20:51:55 +04:00
{
const struct logical_volume *lv = (const struct logical_volume *) data;
const char *name;
2005-06-01 20:51:55 +04:00
if ((name = lv_mirror_log_dup(mem, lv)))
return dm_report_field_string(rh, field, &name);
2005-06-01 20:51:55 +04:00
return _field_set_value(field, "", NULL);
2005-06-01 20:51:55 +04:00
}
static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
char *repstr, *lvname;
size_t len;
if (lv_is_visible(lv))
return dm_report_field_string(rh, field, &lv->name);
len = strlen(lv->name) + 3;
if (!(repstr = dm_pool_zalloc(mem, len))) {
log_error("dm_pool_alloc failed");
return 0;
}
2006-08-21 16:54:53 +04:00
if (dm_snprintf(repstr, len, "[%s]", lv->name) < 0) {
log_error("lvname snprintf failed");
return 0;
}
if (!(lvname = dm_pool_strdup(mem, lv->name))) {
log_error("dm_pool_strdup failed");
return 0;
}
return _field_set_value(field, repstr, lvname);
}
static int _datalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
const struct lv_segment *seg = (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) ? first_seg(lv) : NULL;
if (seg)
return _lvname_disp(rh, mem, field, seg_lv(seg, 0), private);
return _field_set_value(field, "", NULL);
}
static int _metadatalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
const struct lv_segment *seg = (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) ? first_seg(lv) : NULL;
if (seg)
return _lvname_disp(rh, mem, field, seg->metadata_lv, private);
return _field_set_value(field, "", NULL);
}
static int _poollv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
struct lv_segment *seg = (lv_is_thin_volume(lv) || lv_is_cache(lv)) ?
first_seg(lv) : NULL;
if (seg)
return _lvname_disp(rh, mem, field, seg->pool_lv, private);
return _field_set_value(field, "", NULL);
}
static int _lvpath_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
char *repstr;
if (!(repstr = lv_path_dup(mem, lv)))
return_0;
return _field_set_value(field, repstr, NULL);
}
static int _origin_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
const struct lv_segment *seg = first_seg(lv);
if (lv_is_cow(lv))
return _lvname_disp(rh, mem, field, origin_from_cow(lv), private);
if (lv_is_cache(lv))
return _lvname_disp(rh, mem, field, seg_lv(seg, 0), private);
if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
return _lvname_disp(rh, mem, field, first_seg(lv)->origin, private);
if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv)
return _lvname_disp(rh, mem, field, first_seg(lv)->external_lv, private);
return _field_set_value(field, "", NULL);
}
static int _movepv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
2003-05-06 16:06:02 +04:00
{
const struct logical_volume *lv = (const struct logical_volume *) data;
const char *name;
if ((name = lv_move_pv_dup(mem, lv)))
return dm_report_field_string(rh, field, &name);
return _field_set_value(field, "", NULL);
2003-05-06 16:06:02 +04:00
}
static int _convertlv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
const char *name;
if ((name = lv_convert_lv_dup(mem, lv)))
return dm_report_field_string(rh, field, &name);
return _field_set_value(field, "", NULL);
}
static int _size32_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const uint32_t size = *(const uint32_t *) data;
const char *disp, *repstr;
uint64_t *sortval;
2008-01-30 16:19:47 +03:00
if (!*(disp = display_size_units(private, (uint64_t) size)))
return_0;
if (!(repstr = dm_pool_strdup(mem, disp))) {
log_error("dm_pool_strdup failed");
return 0;
}
if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
log_error("dm_pool_alloc failed");
return 0;
}
*sortval = (uint64_t) size;
return _field_set_value(field, repstr, sortval);
}
static int _size64_disp(struct dm_report *rh __attribute__((unused)),
struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const uint64_t size = *(const uint64_t *) data;
const char *disp, *repstr;
uint64_t *sortval;
2008-01-30 16:19:47 +03:00
if (!*(disp = display_size_units(private, size)))
return_0;
if (!(repstr = dm_pool_strdup(mem, disp))) {
log_error("dm_pool_strdup failed");
return 0;
}
if (!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
log_error("dm_pool_alloc failed");
return 0;
}
*sortval = size;
return _field_set_value(field, repstr, sortval);
}
static int _uint32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
return dm_report_field_uint32(rh, field, data);
}
static int _int8_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const int32_t val = *(const int8_t *)data;
return dm_report_field_int32(rh, field, &val);
}
static int _int32_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
return dm_report_field_int32(rh, field, data);
}
static int _lvreadahead_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
if (lv->read_ahead == DM_READ_AHEAD_AUTO)
return _field_set_value(field, "auto", &_minusone64);
return _size32_disp(rh, mem, field, &lv->read_ahead, private);
}
static int _lvkreadahead_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data,
void *private)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
uint32_t read_ahead = lv_kernel_read_ahead(lv);
if (read_ahead == UINT32_MAX)
return dm_report_field_int32(rh, field, &_minusone32);
return _size32_disp(rh, mem, field, &read_ahead, private);
}
static int _vgsize_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct volume_group *vg = (const struct volume_group *) data;
uint64_t size = vg_size(vg);
return _size64_disp(rh, mem, field, &size, private);
}
static int _segmonitor_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
char *str;
if (!(str = lvseg_monitor_dup(mem, (const struct lv_segment *)data)))
return_0;
return _field_set_value(field, str, NULL);
}
static int _segstart_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct lv_segment *seg = (const struct lv_segment *) data;
uint64_t start = lvseg_start(seg);
return _size64_disp(rh, mem, field, &start, private);
}
2007-12-20 19:49:37 +03:00
static int _segstartpe_disp(struct dm_report *rh,
struct dm_pool *mem __attribute__((unused)),
2007-12-20 19:49:37 +03:00
struct dm_report_field *field,
const void *data,
void *private __attribute__((unused)))
{
const struct lv_segment *seg = (const struct lv_segment *) data;
return dm_report_field_uint32(rh, field, &seg->le);
}
static int _segsize_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct lv_segment *seg = (const struct lv_segment *) data;
uint64_t size = lvseg_size(seg);
return _size64_disp(rh, mem, field, &size, private);
}
static int _segsizepe_disp(struct dm_report *rh,
struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
const void *data,
void *private __attribute__((unused)))
{
const struct lv_segment *seg = (const struct lv_segment *) data;
return dm_report_field_uint32(rh, field, &seg->len);
}
static int _chunksize_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
2005-09-23 21:06:01 +04:00
{
const struct lv_segment *seg = (const struct lv_segment *) data;
uint64_t size = lvseg_chunksize(seg);
return _size64_disp(rh, mem, field, &size, private);
}
static int _thinzero_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct lv_segment *seg = (const struct lv_segment *) data;
if (seg_is_thin_pool(seg))
return _uint32_disp(rh, mem, field, &seg->zero_new_blocks, private);
return _field_set_value(field, "", &_minusone64);
}
static int _transactionid_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct lv_segment *seg = (const struct lv_segment *) data;
if (seg_is_thin_pool(seg))
return dm_report_field_uint64(rh, field, &seg->transaction_id);
return _field_set_value(field, "", &_minusone64);
}
static int _thinid_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct lv_segment *seg = (const struct lv_segment *) data;
if (seg_is_thin_volume(seg))
return dm_report_field_uint32(rh, field, &seg->device_id);
return _field_set_value(field, "", &_minusone64);
}
static int _discards_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct lv_segment *seg = (const struct lv_segment *) data;
const char *discards_str;
if (seg_is_thin_volume(seg))
seg = first_seg(seg->pool_lv);
if (seg_is_thin_pool(seg)) {
discards_str = get_pool_discards_name(seg->discards);
return dm_report_field_string(rh, field, &discards_str);
}
return _field_set_value(field, "", NULL);
}
static int _originsize_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
uint64_t size = lv_origin_size(lv);
if (size)
return _size64_disp(rh, mem, field, &size, private);
2005-09-23 21:06:01 +04:00
return _field_set_value(field, "", &_zero64);
2005-09-23 21:06:01 +04:00
}
static int _pvused_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct physical_volume *pv =
(const struct physical_volume *) data;
uint64_t used = pv_used(pv);
return _size64_disp(rh, mem, field, &used, private);
}
static int _pvfree_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct physical_volume *pv =
(const struct physical_volume *) data;
uint64_t freespace = pv_free(pv);
return _size64_disp(rh, mem, field, &freespace, private);
}
static int _pvsize_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct physical_volume *pv =
(const struct physical_volume *) data;
uint64_t size = pv_size_field(pv);
return _size64_disp(rh, mem, field, &size, private);
}
static int _devsize_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
2004-08-11 17:15:05 +04:00
{
const struct device *dev = *(const struct device * const *) data;
uint64_t size;
if (!dev || !dev->dev || !dev_get_size(dev, &size))
size = _zero64;
return _size64_disp(rh, mem, field, &size, private);
2004-08-11 17:15:05 +04:00
}
static int _vgfree_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct volume_group *vg = (const struct volume_group *) data;
uint64_t freespace = vg_free(vg);
return _size64_disp(rh, mem, field, &freespace, private);
}
static int _uuid_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
char *repstr;
if (!(repstr = id_format_and_copy(mem, data)))
2008-01-30 16:19:47 +03:00
return_0;
return _field_set_value(field, repstr, NULL);
}
static int _pvuuid_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const struct label *label = (const struct label *) data;
const char *repstr = "";
if (label->dev &&
!(repstr = id_format_and_copy(mem, (const struct id *) label->dev->pvid)))
return_0;
return _field_set_value(field, repstr, NULL);
}
static int _pvmdas_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct physical_volume *pv =
(const struct physical_volume *) data;
uint32_t count = pv_mda_count(pv);
return _uint32_disp(rh, mem, field, &count, private);
}
Define new functions and vgs/pvs fields related to mda ignore. Define a new pvs field, pv_mda_used_count, and a new vgs field, vg_mda_used_count to match the existing pv_mda_count and vg_mda_count. These new fields count the number of mdas that have the 'ignored' bit clear (they are in use on the PV / VG). Also define various supporting functions to implement the counting as well as setting the ignored flag and determining if an mda is ignored. These high level functions call into the lower level location independent mda ignore functions defined by earlier patches. Note that counting ignored mdas in a vg requires traversing both lists and checking for the ignored bit on the mda. The count of 'ignored' mdas then is defined by having the bit set, not by which list the mda is on. The list does determine whether LVM actually does read/write to the mda, though we must count the bits in order to return accurate numbers for the various counts. Also, pv_mda_set_ignored must search both vg lists for ignored mda. If the state changes and needs to be committed to disk, the ignored mda will be on the non-ignored list. Note also in pv_mda_set_ignored(), we must properly manage the mda lists. If we change the ignored state of an mda, we must change any mdas on vg->fid->metadata_areas that correspond to this pv. Also, we may need to allocate a copy of the mda, as is done when fid->metadata_areas is populated from _vg_read(), if we are un-ignoring an ignored mda. Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:33:44 +04:00
static int _pvmdasused_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct physical_volume *pv =
(const struct physical_volume *) data;
uint32_t count = pv_mda_used_count(pv);
Define new functions and vgs/pvs fields related to mda ignore. Define a new pvs field, pv_mda_used_count, and a new vgs field, vg_mda_used_count to match the existing pv_mda_count and vg_mda_count. These new fields count the number of mdas that have the 'ignored' bit clear (they are in use on the PV / VG). Also define various supporting functions to implement the counting as well as setting the ignored flag and determining if an mda is ignored. These high level functions call into the lower level location independent mda ignore functions defined by earlier patches. Note that counting ignored mdas in a vg requires traversing both lists and checking for the ignored bit on the mda. The count of 'ignored' mdas then is defined by having the bit set, not by which list the mda is on. The list does determine whether LVM actually does read/write to the mda, though we must count the bits in order to return accurate numbers for the various counts. Also, pv_mda_set_ignored must search both vg lists for ignored mda. If the state changes and needs to be committed to disk, the ignored mda will be on the non-ignored list. Note also in pv_mda_set_ignored(), we must properly manage the mda lists. If we change the ignored state of an mda, we must change any mdas on vg->fid->metadata_areas that correspond to this pv. Also, we may need to allocate a copy of the mda, as is done when fid->metadata_areas is populated from _vg_read(), if we are un-ignoring an ignored mda. Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:33:44 +04:00
return _uint32_disp(rh, mem, field, &count, private);
}
static int _vgmdas_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct volume_group *vg = (const struct volume_group *) data;
uint32_t count = vg_mda_count(vg);
return _uint32_disp(rh, mem, field, &count, private);
}
Define new functions and vgs/pvs fields related to mda ignore. Define a new pvs field, pv_mda_used_count, and a new vgs field, vg_mda_used_count to match the existing pv_mda_count and vg_mda_count. These new fields count the number of mdas that have the 'ignored' bit clear (they are in use on the PV / VG). Also define various supporting functions to implement the counting as well as setting the ignored flag and determining if an mda is ignored. These high level functions call into the lower level location independent mda ignore functions defined by earlier patches. Note that counting ignored mdas in a vg requires traversing both lists and checking for the ignored bit on the mda. The count of 'ignored' mdas then is defined by having the bit set, not by which list the mda is on. The list does determine whether LVM actually does read/write to the mda, though we must count the bits in order to return accurate numbers for the various counts. Also, pv_mda_set_ignored must search both vg lists for ignored mda. If the state changes and needs to be committed to disk, the ignored mda will be on the non-ignored list. Note also in pv_mda_set_ignored(), we must properly manage the mda lists. If we change the ignored state of an mda, we must change any mdas on vg->fid->metadata_areas that correspond to this pv. Also, we may need to allocate a copy of the mda, as is done when fid->metadata_areas is populated from _vg_read(), if we are un-ignoring an ignored mda. Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:33:44 +04:00
static int _vgmdasused_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct volume_group *vg = (const struct volume_group *) data;
uint32_t count = vg_mda_used_count(vg);
Define new functions and vgs/pvs fields related to mda ignore. Define a new pvs field, pv_mda_used_count, and a new vgs field, vg_mda_used_count to match the existing pv_mda_count and vg_mda_count. These new fields count the number of mdas that have the 'ignored' bit clear (they are in use on the PV / VG). Also define various supporting functions to implement the counting as well as setting the ignored flag and determining if an mda is ignored. These high level functions call into the lower level location independent mda ignore functions defined by earlier patches. Note that counting ignored mdas in a vg requires traversing both lists and checking for the ignored bit on the mda. The count of 'ignored' mdas then is defined by having the bit set, not by which list the mda is on. The list does determine whether LVM actually does read/write to the mda, though we must count the bits in order to return accurate numbers for the various counts. Also, pv_mda_set_ignored must search both vg lists for ignored mda. If the state changes and needs to be committed to disk, the ignored mda will be on the non-ignored list. Note also in pv_mda_set_ignored(), we must properly manage the mda lists. If we change the ignored state of an mda, we must change any mdas on vg->fid->metadata_areas that correspond to this pv. Also, we may need to allocate a copy of the mda, as is done when fid->metadata_areas is populated from _vg_read(), if we are un-ignoring an ignored mda. Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:33:44 +04:00
return _uint32_disp(rh, mem, field, &count, private);
}
static int _vgmdacopies_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct volume_group *vg = (const struct volume_group *) data;
uint32_t count = vg_mda_copies(vg);
if (count == VGMETADATACOPIES_UNMANAGED)
return _field_set_value(field, "unmanaged", &_minusone64);
return _uint32_disp(rh, mem, field, &count, private);
}
static int _vgprofile_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct volume_group *vg = (const struct volume_group *) data;
if (vg->profile)
return dm_report_field_string(rh, field, &vg->profile->name);
return _field_set_value(field, "", NULL);
}
static int _pvmdafree_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct label *label = (const struct label *) data;
uint64_t freespace = lvmcache_info_mda_free(label->info);
return _size64_disp(rh, mem, field, &freespace, private);
}
static int _pvmdasize_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct label *label = (const struct label *) data;
uint64_t min_mda_size = lvmcache_smallest_mda_size(label->info);
return _size64_disp(rh, mem, field, &min_mda_size, private);
}
static int _vgmdasize_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct volume_group *vg = (const struct volume_group *) data;
uint64_t min_mda_size = vg_mda_size(vg);
return _size64_disp(rh, mem, field, &min_mda_size, private);
}
static int _vgmdafree_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct volume_group *vg = (const struct volume_group *) data;
uint64_t freespace = vg_mda_free(vg);
return _size64_disp(rh, mem, field, &freespace, private);
}
static int _lvcount_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct volume_group *vg = (const struct volume_group *) data;
uint32_t count = vg_visible_lvs(vg);
return _uint32_disp(rh, mem, field, &count, private);
}
static int _lvsegcount_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
uint32_t count = dm_list_size(&lv->segments);
return _uint32_disp(rh, mem, field, &count, private);
}
static int _snapcount_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct volume_group *vg = (const struct volume_group *) data;
uint32_t count = snapshot_count(vg);
return _uint32_disp(rh, mem, field, &count, private);
}
static int _snpercent_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
percent_t snap_percent;
if ((lv_is_cow(lv) || lv_is_merging_origin(lv)) &&
lv_snapshot_percent(lv, &snap_percent)) {
if ((snap_percent != PERCENT_INVALID) &&
(snap_percent != PERCENT_MERGE_FAILED))
return _field_set_percent(field, mem, snap_percent);
if (!lv_is_merging_origin(lv))
return _field_set_value(field, "100.00", &_hundred64);
2003-01-21 21:50:50 +03:00
/*
* on activate merge that hasn't started yet would
* otherwise display incorrect snap% in origin
*/
}
return _field_set_value(field, "", &_minusone64);
}
static int _copypercent_disp(struct dm_report *rh __attribute__((unused)),
2009-10-01 05:04:27 +04:00
struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private __attribute__((unused)))
2003-05-06 16:06:02 +04:00
{
const struct logical_volume *lv = (const struct logical_volume *) data;
percent_t percent;
2003-05-06 16:06:02 +04:00
if (((lv_is_raid(lv) && lv_raid_percent(lv, &percent)) ||
2003-05-06 16:06:02 +04:00
((lv->status & (PVMOVE | MIRRORED)) &&
lv_mirror_percent(lv->vg->cmd, lv, 0, &percent, NULL))) &&
(percent != PERCENT_INVALID)) {
percent = copy_percent(lv);
return _field_set_percent(field, mem, percent);
2003-05-06 16:06:02 +04:00
}
return _field_set_value(field, "", &_minusone64);
2003-05-06 16:06:02 +04:00
}
static int _raidsyncaction_disp(struct dm_report *rh __attribute__((unused)),
RAID: Add scrubbing support for RAID LVs New options to 'lvchange' allow users to scrub their RAID LVs. Synopsis: lvchange --syncaction {check|repair} vg/raid_lv RAID scrubbing is the process of reading all the data and parity blocks in an array and checking to see whether they are coherent. 'lvchange' can now initaite the two scrubbing operations: "check" and "repair". "check" will go over the array and recored the number of discrepancies but not repair them. "repair" will correct the discrepancies as it finds them. 'lvchange --syncaction repair vg/raid_lv' is not to be confused with 'lvconvert --repair vg/raid_lv'. The former initiates a background synchronization operation on the array, while the latter is designed to repair/replace failed devices in a mirror or RAID logical volume. Additional reporting has been added for 'lvs' to support the new operations. Two new printable fields (which are not printed by default) have been added: "syncaction" and "mismatches". These can be accessed using the '-o' option to 'lvs', like: lvs -o +syncaction,mismatches vg/lv "syncaction" will print the current synchronization operation that the RAID volume is performing. It can be one of the following: - idle: All sync operations complete (doing nothing) - resync: Initializing an array or recovering after a machine failure - recover: Replacing a device in the array - check: Looking for array inconsistencies - repair: Looking for and repairing inconsistencies The "mismatches" field with print the number of descrepancies found during a check or repair operation. The 'Cpy%Sync' field already available to 'lvs' will print the progress of any of the above syncactions, including check and repair. Finally, the lv_attr field has changed to accomadate the scrubbing operations as well. The role of the 'p'artial character in the lv_attr report field as expanded. "Partial" is really an indicator for the health of a logical volume and it makes sense to extend this include other health indicators as well, specifically: 'm'ismatches: Indicates that there are discrepancies in a RAID LV. This character is shown after a scrubbing operation has detected that portions of the RAID are not coherent. 'r'efresh : Indicates that a device in a RAID array has suffered a failure and the kernel regards it as failed - even though LVM can read the device label and considers the device to be ok. The LV should be 'r'efreshed to notify the kernel that the device is now available, or the device should be 'r'eplaced if it is suspected of failing.
2013-04-12 00:33:59 +04:00
struct dm_pool *mem,
struct dm_report_field *field,
const void *data,
void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
char *sync_action;
if (lv_is_raid(lv) && lv_raid_sync_action(lv, &sync_action))
return _string_disp(rh, mem, field, &sync_action, private);
RAID: Add scrubbing support for RAID LVs New options to 'lvchange' allow users to scrub their RAID LVs. Synopsis: lvchange --syncaction {check|repair} vg/raid_lv RAID scrubbing is the process of reading all the data and parity blocks in an array and checking to see whether they are coherent. 'lvchange' can now initaite the two scrubbing operations: "check" and "repair". "check" will go over the array and recored the number of discrepancies but not repair them. "repair" will correct the discrepancies as it finds them. 'lvchange --syncaction repair vg/raid_lv' is not to be confused with 'lvconvert --repair vg/raid_lv'. The former initiates a background synchronization operation on the array, while the latter is designed to repair/replace failed devices in a mirror or RAID logical volume. Additional reporting has been added for 'lvs' to support the new operations. Two new printable fields (which are not printed by default) have been added: "syncaction" and "mismatches". These can be accessed using the '-o' option to 'lvs', like: lvs -o +syncaction,mismatches vg/lv "syncaction" will print the current synchronization operation that the RAID volume is performing. It can be one of the following: - idle: All sync operations complete (doing nothing) - resync: Initializing an array or recovering after a machine failure - recover: Replacing a device in the array - check: Looking for array inconsistencies - repair: Looking for and repairing inconsistencies The "mismatches" field with print the number of descrepancies found during a check or repair operation. The 'Cpy%Sync' field already available to 'lvs' will print the progress of any of the above syncactions, including check and repair. Finally, the lv_attr field has changed to accomadate the scrubbing operations as well. The role of the 'p'artial character in the lv_attr report field as expanded. "Partial" is really an indicator for the health of a logical volume and it makes sense to extend this include other health indicators as well, specifically: 'm'ismatches: Indicates that there are discrepancies in a RAID LV. This character is shown after a scrubbing operation has detected that portions of the RAID are not coherent. 'r'efresh : Indicates that a device in a RAID array has suffered a failure and the kernel regards it as failed - even though LVM can read the device label and considers the device to be ok. The LV should be 'r'efreshed to notify the kernel that the device is now available, or the device should be 'r'eplaced if it is suspected of failing.
2013-04-12 00:33:59 +04:00
return _field_set_value(field, "", NULL);
RAID: Add scrubbing support for RAID LVs New options to 'lvchange' allow users to scrub their RAID LVs. Synopsis: lvchange --syncaction {check|repair} vg/raid_lv RAID scrubbing is the process of reading all the data and parity blocks in an array and checking to see whether they are coherent. 'lvchange' can now initaite the two scrubbing operations: "check" and "repair". "check" will go over the array and recored the number of discrepancies but not repair them. "repair" will correct the discrepancies as it finds them. 'lvchange --syncaction repair vg/raid_lv' is not to be confused with 'lvconvert --repair vg/raid_lv'. The former initiates a background synchronization operation on the array, while the latter is designed to repair/replace failed devices in a mirror or RAID logical volume. Additional reporting has been added for 'lvs' to support the new operations. Two new printable fields (which are not printed by default) have been added: "syncaction" and "mismatches". These can be accessed using the '-o' option to 'lvs', like: lvs -o +syncaction,mismatches vg/lv "syncaction" will print the current synchronization operation that the RAID volume is performing. It can be one of the following: - idle: All sync operations complete (doing nothing) - resync: Initializing an array or recovering after a machine failure - recover: Replacing a device in the array - check: Looking for array inconsistencies - repair: Looking for and repairing inconsistencies The "mismatches" field with print the number of descrepancies found during a check or repair operation. The 'Cpy%Sync' field already available to 'lvs' will print the progress of any of the above syncactions, including check and repair. Finally, the lv_attr field has changed to accomadate the scrubbing operations as well. The role of the 'p'artial character in the lv_attr report field as expanded. "Partial" is really an indicator for the health of a logical volume and it makes sense to extend this include other health indicators as well, specifically: 'm'ismatches: Indicates that there are discrepancies in a RAID LV. This character is shown after a scrubbing operation has detected that portions of the RAID are not coherent. 'r'efresh : Indicates that a device in a RAID array has suffered a failure and the kernel regards it as failed - even though LVM can read the device label and considers the device to be ok. The LV should be 'r'efreshed to notify the kernel that the device is now available, or the device should be 'r'eplaced if it is suspected of failing.
2013-04-12 00:33:59 +04:00
}
static int _raidmismatchcount_disp(struct dm_report *rh __attribute__((unused)),
RAID: Add scrubbing support for RAID LVs New options to 'lvchange' allow users to scrub their RAID LVs. Synopsis: lvchange --syncaction {check|repair} vg/raid_lv RAID scrubbing is the process of reading all the data and parity blocks in an array and checking to see whether they are coherent. 'lvchange' can now initaite the two scrubbing operations: "check" and "repair". "check" will go over the array and recored the number of discrepancies but not repair them. "repair" will correct the discrepancies as it finds them. 'lvchange --syncaction repair vg/raid_lv' is not to be confused with 'lvconvert --repair vg/raid_lv'. The former initiates a background synchronization operation on the array, while the latter is designed to repair/replace failed devices in a mirror or RAID logical volume. Additional reporting has been added for 'lvs' to support the new operations. Two new printable fields (which are not printed by default) have been added: "syncaction" and "mismatches". These can be accessed using the '-o' option to 'lvs', like: lvs -o +syncaction,mismatches vg/lv "syncaction" will print the current synchronization operation that the RAID volume is performing. It can be one of the following: - idle: All sync operations complete (doing nothing) - resync: Initializing an array or recovering after a machine failure - recover: Replacing a device in the array - check: Looking for array inconsistencies - repair: Looking for and repairing inconsistencies The "mismatches" field with print the number of descrepancies found during a check or repair operation. The 'Cpy%Sync' field already available to 'lvs' will print the progress of any of the above syncactions, including check and repair. Finally, the lv_attr field has changed to accomadate the scrubbing operations as well. The role of the 'p'artial character in the lv_attr report field as expanded. "Partial" is really an indicator for the health of a logical volume and it makes sense to extend this include other health indicators as well, specifically: 'm'ismatches: Indicates that there are discrepancies in a RAID LV. This character is shown after a scrubbing operation has detected that portions of the RAID are not coherent. 'r'efresh : Indicates that a device in a RAID array has suffered a failure and the kernel regards it as failed - even though LVM can read the device label and considers the device to be ok. The LV should be 'r'efreshed to notify the kernel that the device is now available, or the device should be 'r'eplaced if it is suspected of failing.
2013-04-12 00:33:59 +04:00
struct dm_pool *mem,
struct dm_report_field *field,
const void *data,
void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
uint64_t mismatch_count;
if (lv_is_raid(lv) && lv_raid_mismatch_count(lv, &mismatch_count))
return dm_report_field_uint64(rh, field, &mismatch_count);
RAID: Add scrubbing support for RAID LVs New options to 'lvchange' allow users to scrub their RAID LVs. Synopsis: lvchange --syncaction {check|repair} vg/raid_lv RAID scrubbing is the process of reading all the data and parity blocks in an array and checking to see whether they are coherent. 'lvchange' can now initaite the two scrubbing operations: "check" and "repair". "check" will go over the array and recored the number of discrepancies but not repair them. "repair" will correct the discrepancies as it finds them. 'lvchange --syncaction repair vg/raid_lv' is not to be confused with 'lvconvert --repair vg/raid_lv'. The former initiates a background synchronization operation on the array, while the latter is designed to repair/replace failed devices in a mirror or RAID logical volume. Additional reporting has been added for 'lvs' to support the new operations. Two new printable fields (which are not printed by default) have been added: "syncaction" and "mismatches". These can be accessed using the '-o' option to 'lvs', like: lvs -o +syncaction,mismatches vg/lv "syncaction" will print the current synchronization operation that the RAID volume is performing. It can be one of the following: - idle: All sync operations complete (doing nothing) - resync: Initializing an array or recovering after a machine failure - recover: Replacing a device in the array - check: Looking for array inconsistencies - repair: Looking for and repairing inconsistencies The "mismatches" field with print the number of descrepancies found during a check or repair operation. The 'Cpy%Sync' field already available to 'lvs' will print the progress of any of the above syncactions, including check and repair. Finally, the lv_attr field has changed to accomadate the scrubbing operations as well. The role of the 'p'artial character in the lv_attr report field as expanded. "Partial" is really an indicator for the health of a logical volume and it makes sense to extend this include other health indicators as well, specifically: 'm'ismatches: Indicates that there are discrepancies in a RAID LV. This character is shown after a scrubbing operation has detected that portions of the RAID are not coherent. 'r'efresh : Indicates that a device in a RAID array has suffered a failure and the kernel regards it as failed - even though LVM can read the device label and considers the device to be ok. The LV should be 'r'efreshed to notify the kernel that the device is now available, or the device should be 'r'eplaced if it is suspected of failing.
2013-04-12 00:33:59 +04:00
return _field_set_value(field, "", &_minusone64);
RAID: Add writemostly/writebehind support for RAID1 'lvchange' is used to alter a RAID 1 logical volume's write-mostly and write-behind characteristics. The '--writemostly' parameter takes a PV as an argument with an optional trailing character to specify whether to set ('y'), unset ('n'), or toggle ('t') the value. If no trailing character is given, it will set the flag. Synopsis: lvchange [--writemostly <PV>:{t|y|n}] [--writebehind <count>] vg/lv Example: lvchange --writemostly /dev/sdb1:y --writebehind 512 vg/raid1_lv The last character in the 'lv_attr' field is used to show whether a device has the WriteMostly flag set. It is signified with a 'w'. If the device has failed, the 'p'artial flag has priority. Example ("nosync" raid1 with mismatch_cnt and writemostly): [~]# lvs -a --segment vg LV VG Attr #Str Type SSize raid1 vg Rwi---r-m 2 raid1 500.00m [raid1_rimage_0] vg Iwi---r-- 1 linear 500.00m [raid1_rimage_1] vg Iwi---r-w 1 linear 500.00m [raid1_rmeta_0] vg ewi---r-- 1 linear 4.00m [raid1_rmeta_1] vg ewi---r-- 1 linear 4.00m Example (raid1 with mismatch_cnt, writemostly - but failed drive): [~]# lvs -a --segment vg LV VG Attr #Str Type SSize raid1 vg rwi---r-p 2 raid1 500.00m [raid1_rimage_0] vg Iwi---r-- 1 linear 500.00m [raid1_rimage_1] vg Iwi---r-p 1 linear 500.00m [raid1_rmeta_0] vg ewi---r-- 1 linear 4.00m [raid1_rmeta_1] vg ewi---r-p 1 linear 4.00m A new reportable field has been added for writebehind as well. If write-behind has not been set or the LV is not RAID1, the field will be blank. Example (writebehind is set): [~]# lvs -a -o name,attr,writebehind vg LV Attr WBehind lv rwi-a-r-- 512 [lv_rimage_0] iwi-aor-w [lv_rimage_1] iwi-aor-- [lv_rmeta_0] ewi-aor-- [lv_rmeta_1] ewi-aor-- Example (writebehind is not set): [~]# lvs -a -o name,attr,writebehind vg LV Attr WBehind lv rwi-a-r-- [lv_rimage_0] iwi-aor-w [lv_rimage_1] iwi-aor-- [lv_rmeta_0] ewi-aor-- [lv_rmeta_1] ewi-aor--
2013-04-15 22:59:46 +04:00
}
static int _raidwritebehind_disp(struct dm_report *rh __attribute__((unused)),
RAID: Add writemostly/writebehind support for RAID1 'lvchange' is used to alter a RAID 1 logical volume's write-mostly and write-behind characteristics. The '--writemostly' parameter takes a PV as an argument with an optional trailing character to specify whether to set ('y'), unset ('n'), or toggle ('t') the value. If no trailing character is given, it will set the flag. Synopsis: lvchange [--writemostly <PV>:{t|y|n}] [--writebehind <count>] vg/lv Example: lvchange --writemostly /dev/sdb1:y --writebehind 512 vg/raid1_lv The last character in the 'lv_attr' field is used to show whether a device has the WriteMostly flag set. It is signified with a 'w'. If the device has failed, the 'p'artial flag has priority. Example ("nosync" raid1 with mismatch_cnt and writemostly): [~]# lvs -a --segment vg LV VG Attr #Str Type SSize raid1 vg Rwi---r-m 2 raid1 500.00m [raid1_rimage_0] vg Iwi---r-- 1 linear 500.00m [raid1_rimage_1] vg Iwi---r-w 1 linear 500.00m [raid1_rmeta_0] vg ewi---r-- 1 linear 4.00m [raid1_rmeta_1] vg ewi---r-- 1 linear 4.00m Example (raid1 with mismatch_cnt, writemostly - but failed drive): [~]# lvs -a --segment vg LV VG Attr #Str Type SSize raid1 vg rwi---r-p 2 raid1 500.00m [raid1_rimage_0] vg Iwi---r-- 1 linear 500.00m [raid1_rimage_1] vg Iwi---r-p 1 linear 500.00m [raid1_rmeta_0] vg ewi---r-- 1 linear 4.00m [raid1_rmeta_1] vg ewi---r-p 1 linear 4.00m A new reportable field has been added for writebehind as well. If write-behind has not been set or the LV is not RAID1, the field will be blank. Example (writebehind is set): [~]# lvs -a -o name,attr,writebehind vg LV Attr WBehind lv rwi-a-r-- 512 [lv_rimage_0] iwi-aor-w [lv_rimage_1] iwi-aor-- [lv_rmeta_0] ewi-aor-- [lv_rmeta_1] ewi-aor-- Example (writebehind is not set): [~]# lvs -a -o name,attr,writebehind vg LV Attr WBehind lv rwi-a-r-- [lv_rimage_0] iwi-aor-w [lv_rimage_1] iwi-aor-- [lv_rmeta_0] ewi-aor-- [lv_rmeta_1] ewi-aor--
2013-04-15 22:59:46 +04:00
struct dm_pool *mem,
struct dm_report_field *field,
const void *data,
void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
if (lv_is_raid_type(lv) && first_seg(lv)->writebehind)
return dm_report_field_uint32(rh, field, &first_seg(lv)->writebehind);
RAID: Add writemostly/writebehind support for RAID1 'lvchange' is used to alter a RAID 1 logical volume's write-mostly and write-behind characteristics. The '--writemostly' parameter takes a PV as an argument with an optional trailing character to specify whether to set ('y'), unset ('n'), or toggle ('t') the value. If no trailing character is given, it will set the flag. Synopsis: lvchange [--writemostly <PV>:{t|y|n}] [--writebehind <count>] vg/lv Example: lvchange --writemostly /dev/sdb1:y --writebehind 512 vg/raid1_lv The last character in the 'lv_attr' field is used to show whether a device has the WriteMostly flag set. It is signified with a 'w'. If the device has failed, the 'p'artial flag has priority. Example ("nosync" raid1 with mismatch_cnt and writemostly): [~]# lvs -a --segment vg LV VG Attr #Str Type SSize raid1 vg Rwi---r-m 2 raid1 500.00m [raid1_rimage_0] vg Iwi---r-- 1 linear 500.00m [raid1_rimage_1] vg Iwi---r-w 1 linear 500.00m [raid1_rmeta_0] vg ewi---r-- 1 linear 4.00m [raid1_rmeta_1] vg ewi---r-- 1 linear 4.00m Example (raid1 with mismatch_cnt, writemostly - but failed drive): [~]# lvs -a --segment vg LV VG Attr #Str Type SSize raid1 vg rwi---r-p 2 raid1 500.00m [raid1_rimage_0] vg Iwi---r-- 1 linear 500.00m [raid1_rimage_1] vg Iwi---r-p 1 linear 500.00m [raid1_rmeta_0] vg ewi---r-- 1 linear 4.00m [raid1_rmeta_1] vg ewi---r-p 1 linear 4.00m A new reportable field has been added for writebehind as well. If write-behind has not been set or the LV is not RAID1, the field will be blank. Example (writebehind is set): [~]# lvs -a -o name,attr,writebehind vg LV Attr WBehind lv rwi-a-r-- 512 [lv_rimage_0] iwi-aor-w [lv_rimage_1] iwi-aor-- [lv_rmeta_0] ewi-aor-- [lv_rmeta_1] ewi-aor-- Example (writebehind is not set): [~]# lvs -a -o name,attr,writebehind vg LV Attr WBehind lv rwi-a-r-- [lv_rimage_0] iwi-aor-w [lv_rimage_1] iwi-aor-- [lv_rmeta_0] ewi-aor-- [lv_rmeta_1] ewi-aor--
2013-04-15 22:59:46 +04:00
return _field_set_value(field, "", &_minusone64);
RAID: Add scrubbing support for RAID LVs New options to 'lvchange' allow users to scrub their RAID LVs. Synopsis: lvchange --syncaction {check|repair} vg/raid_lv RAID scrubbing is the process of reading all the data and parity blocks in an array and checking to see whether they are coherent. 'lvchange' can now initaite the two scrubbing operations: "check" and "repair". "check" will go over the array and recored the number of discrepancies but not repair them. "repair" will correct the discrepancies as it finds them. 'lvchange --syncaction repair vg/raid_lv' is not to be confused with 'lvconvert --repair vg/raid_lv'. The former initiates a background synchronization operation on the array, while the latter is designed to repair/replace failed devices in a mirror or RAID logical volume. Additional reporting has been added for 'lvs' to support the new operations. Two new printable fields (which are not printed by default) have been added: "syncaction" and "mismatches". These can be accessed using the '-o' option to 'lvs', like: lvs -o +syncaction,mismatches vg/lv "syncaction" will print the current synchronization operation that the RAID volume is performing. It can be one of the following: - idle: All sync operations complete (doing nothing) - resync: Initializing an array or recovering after a machine failure - recover: Replacing a device in the array - check: Looking for array inconsistencies - repair: Looking for and repairing inconsistencies The "mismatches" field with print the number of descrepancies found during a check or repair operation. The 'Cpy%Sync' field already available to 'lvs' will print the progress of any of the above syncactions, including check and repair. Finally, the lv_attr field has changed to accomadate the scrubbing operations as well. The role of the 'p'artial character in the lv_attr report field as expanded. "Partial" is really an indicator for the health of a logical volume and it makes sense to extend this include other health indicators as well, specifically: 'm'ismatches: Indicates that there are discrepancies in a RAID LV. This character is shown after a scrubbing operation has detected that portions of the RAID are not coherent. 'r'efresh : Indicates that a device in a RAID array has suffered a failure and the kernel regards it as failed - even though LVM can read the device label and considers the device to be ok. The LV should be 'r'efreshed to notify the kernel that the device is now available, or the device should be 'r'eplaced if it is suspected of failing.
2013-04-12 00:33:59 +04:00
}
static int _raidminrecoveryrate_disp(struct dm_report *rh __attribute__((unused)),
struct dm_pool *mem,
struct dm_report_field *field,
const void *data,
void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
if (lv_is_raid_type(lv) && first_seg(lv)->min_recovery_rate)
return dm_report_field_uint32(rh, field,
&first_seg(lv)->min_recovery_rate);
return _field_set_value(field, "", &_minusone64);
}
static int _raidmaxrecoveryrate_disp(struct dm_report *rh __attribute__((unused)),
struct dm_pool *mem,
struct dm_report_field *field,
const void *data,
void *private __attribute__((unused)))
{
const struct logical_volume *lv = (const struct logical_volume *) data;
if (lv_is_raid_type(lv) && first_seg(lv)->max_recovery_rate)
return dm_report_field_uint32(rh, field,
&first_seg(lv)->max_recovery_rate);
return _field_set_value(field, "", &_minusone64);
}
/* Called only with lv_is_thin_pool/volume */
static int _dtpercent_disp(int metadata, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
percent_t percent;
/* Suppress data percent if not using driver */
/* cannot use lv_is_active_locally - need to check for layer -tpool */
if (!lv_info(lv->vg->cmd, lv, 1, NULL, 0, 0))
return _field_set_value(field, "", &_minusone64);
if (lv_is_thin_pool(lv)) {
if (!lv_thin_pool_percent(lv, metadata, &percent))
return_0;
} else { /* thin_volume */
if (!lv_thin_percent(lv, 0, &percent))
return_0;
}
return _field_set_percent(field, mem, percent);
}
static int _datapercent_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
if (lv_is_cow(lv))
return _snpercent_disp(rh, mem, field, data, private);
if (lv_is_thin_pool(lv) || lv_is_thin_volume(lv))
return _dtpercent_disp(0, mem, field, data, private);
return _field_set_value(field, "", &_minusone64);
}
static int _metadatapercent_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
if (lv_is_thin_pool(lv))
return _dtpercent_disp(1, mem, field, data, private);
return _field_set_value(field, "", &_minusone64);
}
static int _lvmetadatasize_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
uint64_t size;
if (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) {
size = lv_metadata_size(lv);
return _size64_disp(rh, mem, field, &size, private);
}
return _field_set_value(field, "", &_minusone64);
}
static int _thincount_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct lv_segment *seg = (const struct lv_segment *) data;
uint32_t count;
if (seg_is_thin_pool(seg)) {
count = dm_list_size(&seg->lv->segs_using_this_lv);
return _uint32_disp(rh, mem, field, &count, private);
}
return _field_set_value(field, "", &_minusone64);
}
static int _lvtime_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
char *repstr;
uint64_t *sortval;
if (!(repstr = lv_time_dup(mem, lv)) ||
!(sortval = dm_pool_alloc(mem, sizeof(uint64_t)))) {
log_error("Failed to allocate buffer for time.");
return 0;
}
*sortval = lv->timestamp;
return _field_set_value(field, repstr, sortval);
}
static int _lvhost_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
char *repstr;
if (!(repstr = lv_host_dup(mem, lv))) {
log_error("Failed to allocate buffer for host.");
return 0;
}
return _field_set_value(field, repstr, NULL);
}
static int _lvactive_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)
{
char *repstr;
if (!(repstr = lv_active_dup(mem, (const struct logical_volume *) data))) {
log_error("Failed to allocate buffer for active.");
return 0;
}
return _field_set_value(field, repstr, NULL);
}
/* Report object types */
/* necessary for displaying something for PVs not belonging to VG */
static struct format_instance _dummy_fid = {
.metadata_areas_in_use = { &(_dummy_fid.metadata_areas_in_use), &(_dummy_fid.metadata_areas_in_use) },
.metadata_areas_ignored = { &(_dummy_fid.metadata_areas_ignored), &(_dummy_fid.metadata_areas_ignored) },
};
static struct volume_group _dummy_vg = {
.fid = &_dummy_fid,
.name = "",
.system_id = (char *) "",
.pvs = { &(_dummy_vg.pvs), &(_dummy_vg.pvs) },
.lvs = { &(_dummy_vg.lvs), &(_dummy_vg.lvs) },
.tags = { &(_dummy_vg.tags), &(_dummy_vg.tags) },
};
static void *_obj_get_vg(void *obj)
{
struct volume_group *vg = ((struct lvm_report_object *)obj)->vg;
return vg ? vg : &_dummy_vg;
}
static void *_obj_get_lv(void *obj)
{
return ((struct lvm_report_object *)obj)->lv;
}
static void *_obj_get_pv(void *obj)
{
return ((struct lvm_report_object *)obj)->pv;
}
static void *_obj_get_label(void *obj)
{
return ((struct lvm_report_object *)obj)->label;
}
static void *_obj_get_seg(void *obj)
{
return ((struct lvm_report_object *)obj)->seg;
}
static void *_obj_get_pvseg(void *obj)
{
return ((struct lvm_report_object *)obj)->pvseg;
}
static void *_obj_get_devtypes(void *obj)
{
return obj;
}
static const struct dm_report_object_type _report_types[] = {
{ VGS, "Volume Group", "vg_", _obj_get_vg },
{ LVS, "Logical Volume", "lv_", _obj_get_lv },
{ PVS, "Physical Volume", "pv_", _obj_get_pv },
{ LABEL, "Physical Volume Label", "pv_", _obj_get_label },
{ SEGS, "Logical Volume Segment", "seg_", _obj_get_seg },
{ PVSEGS, "Physical Volume Segment", "pvseg_", _obj_get_pvseg },
{ 0, "", "", NULL },
};
static const struct dm_report_object_type _devtypes_report_types[] = {
{ DEVTYPES, "Device Types", "devtype_", _obj_get_devtypes },
{ 0, "", "", NULL },
};
/*
* Import column definitions
*/
#define STR DM_REPORT_FIELD_TYPE_STRING
#define NUM DM_REPORT_FIELD_TYPE_NUMBER
#define FIELD(type, strct, sorttype, head, field, width, func, id, desc, writeable) \
{type, sorttype, offsetof(type_ ## strct, field), width, \
#id, head, &_ ## func ## _disp, desc},
typedef struct physical_volume type_pv;
typedef struct logical_volume type_lv;
typedef struct volume_group type_vg;
typedef struct lv_segment type_seg;
typedef struct pv_segment type_pvseg;
typedef struct label type_label;
typedef dev_known_type_t type_devtype;
static const struct dm_report_field_type _fields[] = {
#include "columns.h"
{0, 0, 0, 0, "", "", NULL, NULL},
};
static const struct dm_report_field_type _devtypes_fields[] = {
#include "columns-devtypes.h"
{0, 0, 0, 0, "", "", NULL, NULL},
};
#undef STR
#undef NUM
#undef FIELD
void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
2007-07-10 22:20:00 +04:00
report_type_t *report_type, const char *separator,
2008-06-25 01:21:04 +04:00
int aligned, int buffered, int headings, int field_prefixes,
2008-06-25 02:48:53 +04:00
int quoted, int columns_as_rows)
{
uint32_t report_flags = 0;
int devtypes_report = *report_type & DEVTYPES ? 1 : 0;
void *rh;
if (aligned)
report_flags |= DM_REPORT_OUTPUT_ALIGNED;
if (buffered)
report_flags |= DM_REPORT_OUTPUT_BUFFERED;
if (headings)
report_flags |= DM_REPORT_OUTPUT_HEADINGS;
2008-06-06 23:28:35 +04:00
if (field_prefixes)
report_flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX;
2008-06-25 01:21:04 +04:00
if (!quoted)
report_flags |= DM_REPORT_OUTPUT_FIELD_UNQUOTED;
2008-06-25 02:48:53 +04:00
if (columns_as_rows)
report_flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS;
rh = dm_report_init(report_type, devtypes_report ? _devtypes_report_types : _report_types,
devtypes_report ? _devtypes_fields : _fields, format,
separator, report_flags, keys, cmd);
if (rh && field_prefixes)
2008-06-06 23:28:35 +04:00
dm_report_set_output_field_name_prefix(rh, "lvm2_");
return rh;
}
/*
* Create a row of data for an object
*/
int report_object(void *handle, struct volume_group *vg,
struct logical_volume *lv, struct physical_volume *pv,
struct lv_segment *seg, struct pv_segment *pvseg,
struct label *label)
{
struct lvm_report_object obj;
/* The two format fields might as well match. */
if (!vg && pv)
_dummy_fid.fmt = pv->fmt;
obj.vg = vg;
obj.lv = lv;
obj.pv = pv;
obj.seg = seg;
obj.pvseg = pvseg;
obj.label = label ? label : (pv ? pv_label(pv) : NULL);
2004-05-05 22:23:11 +04:00
return dm_report_object(handle, &obj);
}
static int _report_devtype_single(void *handle, const dev_known_type_t *devtype)
{
return dm_report_object(handle, (void *)devtype);
}
int report_devtypes(void *handle)
{
int devtypeind = 0;
while (_dev_known_types[devtypeind].name[0])
if (!_report_devtype_single(handle, &_dev_known_types[devtypeind++]))
return 0;
return 1;
}