mirror of
git://sourceware.org/git/lvm2.git
synced 2026-01-18 00:34:07 +03:00
Compare commits
256 Commits
v2_02_131
...
dev-mcsont
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf06d942b8 | ||
|
|
83d3cc76f3 | ||
|
|
89574055f7 | ||
|
|
7831a65091 | ||
|
|
15a97cc610 | ||
|
|
3f1c63c812 | ||
|
|
dd52721b68 | ||
|
|
7f125c1116 | ||
|
|
5b04eda93f | ||
|
|
77c31d0c39 | ||
|
|
baf320455b | ||
|
|
bb4d3fa7a7 | ||
|
|
3e18b101a0 | ||
|
|
df190dcfa5 | ||
|
|
e149fe7fdf | ||
|
|
77605457e7 | ||
|
|
0d5b1294f0 | ||
|
|
097d14e64e | ||
|
|
17196103e0 | ||
|
|
ccfc09f79b | ||
|
|
9a3b64e81a | ||
|
|
c2e88d1107 | ||
|
|
406d8ff332 | ||
|
|
00348c0a63 | ||
|
|
ccb8da404d | ||
|
|
28e54032c0 | ||
|
|
bca55c9b20 | ||
|
|
f104a81932 | ||
|
|
3720eb63be | ||
|
|
8b5525383f | ||
|
|
f58c634103 | ||
|
|
175119fdcd | ||
|
|
33a8a2febf | ||
|
|
f32f0bd2a7 | ||
|
|
99237f0908 | ||
|
|
099466939e | ||
|
|
b3c81d02c9 | ||
|
|
5886ff64eb | ||
|
|
a4418b34c1 | ||
|
|
65ec00ce20 | ||
|
|
6e1e0e8813 | ||
|
|
4159680a0e | ||
|
|
76cff10a73 | ||
|
|
1af2ab10d0 | ||
|
|
729f489009 | ||
|
|
5d76bdcdbd | ||
|
|
3b5939bbbb | ||
|
|
a2dd1f6e19 | ||
|
|
c301cc5d38 | ||
|
|
ba41ee1dc9 | ||
|
|
b702d67747 | ||
|
|
44ba862674 | ||
|
|
6624833839 | ||
|
|
b29593378f | ||
|
|
428ca9b120 | ||
|
|
f898cf7539 | ||
|
|
844b009584 | ||
|
|
9ef820a2a5 | ||
|
|
40eea582ae | ||
|
|
b780d329aa | ||
|
|
8f269697d2 | ||
|
|
98d81a43ea | ||
|
|
1a74171ca5 | ||
|
|
51735f09f7 | ||
|
|
3a42c13ccf | ||
|
|
8b965bd3d5 | ||
|
|
1a7bea0f0f | ||
|
|
b5b2a54834 | ||
|
|
21748a8630 | ||
|
|
e5b686d693 | ||
|
|
87a39d8bac | ||
|
|
cff1c728d8 | ||
|
|
2786cd27da | ||
|
|
1a2d0a0c72 | ||
|
|
b1319e0402 | ||
|
|
8be60e6a65 | ||
|
|
39cffa4e9b | ||
|
|
2af696c32f | ||
|
|
4284ba65eb | ||
|
|
aeec62ad19 | ||
|
|
12aa56d298 | ||
|
|
9156c5d088 | ||
|
|
466a1c72b7 | ||
|
|
81e9ab3156 | ||
|
|
15dbd4b56a | ||
|
|
e2ea2a8147 | ||
|
|
941c6354db | ||
|
|
02eb000f51 | ||
|
|
efc76ca33d | ||
|
|
590091a4fa | ||
|
|
9488cbdd0b | ||
|
|
fa9e41d2e3 | ||
|
|
6b0bc5b2d9 | ||
|
|
7ff5b03e5e | ||
|
|
91350f5c6a | ||
|
|
9c5c9e2355 | ||
|
|
cde12cbe9e | ||
|
|
ab6d16a8a5 | ||
|
|
09a62cca0c | ||
|
|
075f85dcb5 | ||
|
|
d2c4ce254b | ||
|
|
7b78d496bf | ||
|
|
19e272ba53 | ||
|
|
73e679f33f | ||
|
|
a0d819172f | ||
|
|
0aee04288e | ||
|
|
ef4d69f456 | ||
|
|
c15649b3af | ||
|
|
f67a52677b | ||
|
|
392248186e | ||
|
|
33465066c5 | ||
|
|
a5c4c4efbd | ||
|
|
83d475626a | ||
|
|
1ea7e2634d | ||
|
|
23d9b17a7b | ||
|
|
c3bfe07f2a | ||
|
|
508f0f5a21 | ||
|
|
df34fcdafd | ||
|
|
a6d1c8ac65 | ||
|
|
7c36d7c90c | ||
|
|
bbef4edd06 | ||
|
|
3f1a3b7090 | ||
|
|
a91fbe9d27 | ||
|
|
ccc39be053 | ||
|
|
0cf787a377 | ||
|
|
acc70de439 | ||
|
|
cf1c2da836 | ||
|
|
c4cc5eabfe | ||
|
|
8cc21354c2 | ||
|
|
2cb1f6eafe | ||
|
|
9322918406 | ||
|
|
83f00e9156 | ||
|
|
4f9e7f692e | ||
|
|
4b586ad3c2 | ||
|
|
256e432e78 | ||
|
|
51ff7d5ed8 | ||
|
|
49e11102c7 | ||
|
|
a11cd2ca2d | ||
|
|
f9926e7e6c | ||
|
|
76ea01dd20 | ||
|
|
362558cd66 | ||
|
|
09a8479cb7 | ||
|
|
0a633750f1 | ||
|
|
0e2261dbd1 | ||
|
|
842a7a17e3 | ||
|
|
f4fb97c850 | ||
|
|
8b9533f38f | ||
|
|
903e9af1b2 | ||
|
|
e261af52eb | ||
|
|
3f03d46fc1 | ||
|
|
0e27210308 | ||
|
|
13086c2523 | ||
|
|
42a9c8b4a6 | ||
|
|
e50583d721 | ||
|
|
c90363b585 | ||
|
|
915f0faac1 | ||
|
|
0641e3a5fd | ||
|
|
11a084cf42 | ||
|
|
d60794c3a3 | ||
|
|
1b1c01a27b | ||
|
|
72d700b064 | ||
|
|
86b04ebd19 | ||
|
|
7e1c08bb6a | ||
|
|
c7b4359ff4 | ||
|
|
5695c6aca6 | ||
|
|
5ac81657e5 | ||
|
|
5bd63df237 | ||
|
|
75420282e1 | ||
|
|
38df48d108 | ||
|
|
21a8ac0cd3 | ||
|
|
1f30ba6178 | ||
|
|
8733a8d890 | ||
|
|
5446d17756 | ||
|
|
c9ff5c8223 | ||
|
|
d99dd4086d | ||
|
|
09981afc1c | ||
|
|
3d03e504cd | ||
|
|
e04424e87e | ||
|
|
277dd0aa7a | ||
|
|
ded9452174 | ||
|
|
4b1cadbd87 | ||
|
|
2506275c3b | ||
|
|
5f7a94a03e | ||
|
|
df59db6048 | ||
|
|
b33d7586e7 | ||
|
|
fb957ef322 | ||
|
|
5e5d48348b | ||
|
|
26da6a3e10 | ||
|
|
4c2cc782aa | ||
|
|
05e7fdd5ce | ||
|
|
796e3fb7e4 | ||
|
|
867a36b419 | ||
|
|
a139275eca | ||
|
|
efcb3bbc8d | ||
|
|
309979d578 | ||
|
|
c805fa7c40 | ||
|
|
634bf8c953 | ||
|
|
be393f6722 | ||
|
|
d94ff20927 | ||
|
|
0173c260d8 | ||
|
|
9d815e5f5a | ||
|
|
7097663ddd | ||
|
|
eab099b221 | ||
|
|
3036620b48 | ||
|
|
d40830a2b1 | ||
|
|
028715b0f0 | ||
|
|
4a74e19f80 | ||
|
|
e773e71910 | ||
|
|
39a97d86f0 | ||
|
|
41fe225b0d | ||
|
|
1945a0f504 | ||
|
|
4e60e62444 | ||
|
|
96a6210198 | ||
|
|
192d9ad977 | ||
|
|
cb82919b0d | ||
|
|
28aff5d240 | ||
|
|
532b2d2d4e | ||
|
|
214e2cddf6 | ||
|
|
0ce150280e | ||
|
|
3a8a37187d | ||
|
|
629398d0f2 | ||
|
|
fd773dffb2 | ||
|
|
001f747963 | ||
|
|
2081071bee | ||
|
|
47f623d64b | ||
|
|
7e63364529 | ||
|
|
2e5bde4a77 | ||
|
|
cfe869692f | ||
|
|
a61f3c5316 | ||
|
|
ce80d73684 | ||
|
|
804c25a81a | ||
|
|
a54b4bba35 | ||
|
|
0a01c5aa36 | ||
|
|
f01b7afa19 | ||
|
|
ffa7b37b28 | ||
|
|
f61a394be4 | ||
|
|
c2ea5b3dee | ||
|
|
199697accf | ||
|
|
cb8f29d147 | ||
|
|
0e3042f488 | ||
|
|
f644431346 | ||
|
|
83a52c07b7 | ||
|
|
7d1dd5f52d | ||
|
|
330d584617 | ||
|
|
11d6f81316 | ||
|
|
f9c8cefd06 | ||
|
|
791e76ff70 | ||
|
|
e0d915a873 | ||
|
|
90ad817a43 | ||
|
|
5bc8c713e2 | ||
|
|
6c0b4a2769 | ||
|
|
afdae26c71 | ||
|
|
b5022102bb | ||
|
|
b7410c95cf | ||
|
|
fcfca57e2e | ||
|
|
0ac10bb23a |
@@ -234,7 +234,7 @@ ifneq ($(shell which ctags),)
|
||||
.PHONY: tags
|
||||
tags:
|
||||
test -z "$(shell find $(top_srcdir) -type f -name '*.[ch]' -newer tags 2>/dev/null | head -1)" || $(RM) tags
|
||||
test -f tags || find $(top_srcdir) -maxdepth 4 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
||||
test -f tags || find $(top_srcdir) -maxdepth 5 -type f -name '*.[ch]' -exec ctags -a '{}' +
|
||||
|
||||
CLEAN_TARGETS += tags
|
||||
endif
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.02.108-git (2015-09-15)
|
||||
1.02.111-git (2015-10-30)
|
||||
|
||||
43
WHATS_NEW
43
WHATS_NEW
@@ -1,3 +1,46 @@
|
||||
Version 2.02.134 -
|
||||
====================================
|
||||
|
||||
Version 2.02.133 - 30th October 2015
|
||||
====================================
|
||||
Support repeated -o|--options for reporting commands.
|
||||
Support -o- and -o# for reporting commands to remove and compact fields.
|
||||
Fix missing PVs from pvs output if vgremove is run concurrently.
|
||||
Remove unwanted error message when running pvs/vgs/lvs and vgremove at once.
|
||||
Check newly created VG's metadata do not overlap in metadata ring buffer.
|
||||
Check metadata area size is at least the minimum size defined for the format.
|
||||
Thin pool targets uses low_water_mark from profile.
|
||||
Dropping 'yet' from error of unsupported thick snapshot of snapshots.
|
||||
Do not support unpartitioned DASD devices with CDL formatted with pvcreate.
|
||||
For thins use flush for suspend only when volume size is reduced.
|
||||
Enable code which detects the need of flush during suspend.
|
||||
Ensure --use-policy will resize volume to fit below threshold.
|
||||
Correct percentage evaluation when checking thin-pool over threshold.
|
||||
Fix lvmcache to move PV from VG to orphans if VG is removed and lvmetad used.
|
||||
Fix lvmcache to not cache even invalid info about PV which got removed.
|
||||
Support checking of memlock daemon counter.
|
||||
Allow all log levels to be used with the lvmetad -l option.
|
||||
Add optional shutdown when idle support for lvmetad.
|
||||
Fix missing in-sync progress info while lvconvert used with lvmpolld.
|
||||
Add report/compact_output_cols to lvm.conf to define report cols to compact.
|
||||
Do not change logging in lvm2 library when it's already set.
|
||||
Check for enough space in thin-pool in command before creating new thin.
|
||||
Make libblkid detect all copies of the same signature if use_blkid_wiping=1.
|
||||
Fix vgimportclone with -n to not add number unnecessarily to base VG name.
|
||||
Cleanup vgimportclone script and remove dependency on awk, grep, cut and tr.
|
||||
Add vg_missing_pv_count report field to report number of missing PVs in a VG.
|
||||
Properly identify internal LV holding sanlock locks within lv_role field.
|
||||
Add metadata_devices and seg_metadata_le_ranges report fields for raid vols.
|
||||
Fix lvm2-{activation,clvmd,cmirrord,monitor} service to exec before mounting.
|
||||
|
||||
Version 2.02.132 - 22nd September 2015
|
||||
======================================
|
||||
Fix lvmconf to set locking_type=2 if external locking library is requested.
|
||||
Remove verbose message when rescanning an unchanged device. (2.02.119)
|
||||
Add origin_uuid, mirror_log_uuid, move_pv_uuid, convert_lv_uuid report fields.
|
||||
Add pool_lv_uuid, metadata_lv_uuid, data_lv_uuid reporting fields.
|
||||
Fix PV label processing failure after pvcreate in lvm shell with lvmetad.
|
||||
|
||||
Version 2.02.131 - 15th September 2015
|
||||
======================================
|
||||
Rename 'make install_full_man' to install_all_man and add all_man target.
|
||||
|
||||
41
WHATS_NEW_DM
41
WHATS_NEW_DM
@@ -1,3 +1,44 @@
|
||||
Version 1.02.111 -
|
||||
====================================
|
||||
|
||||
Version 1.02.110 - 30th October 2015
|
||||
====================================
|
||||
Disable thin monitoring plugin when it fails too often (>10 times).
|
||||
Fix/restore parsing of empty field '-' when processing dmeventd event.
|
||||
Enhance dm_tree_node_size_changed() to recognize size reduction.
|
||||
Support exit on idle for dmenventd (1 hour).
|
||||
Add support to allow unmonitor device from plugin itself.
|
||||
New design for thread co-operation in dmeventd.
|
||||
Dmeventd read device status with 'noflush'.
|
||||
Dmeventd closes control device when no device is monitored.
|
||||
Thin plugin for dmeventd improved percentage usage.
|
||||
Snapshot plugin for dmeventd improved percentage usage.
|
||||
Add dm_hold_control_dev to allow holding of control device open.
|
||||
Add dm_report_compact_given_fields to remove given empty fields from report.
|
||||
Use libdm status parsing and local mem raid dmeventd plugin.
|
||||
Use local mem pool and lock only lvm2 execution for mirror dmeventd plugin.
|
||||
Lock protect only lvm2 execution for snapshot and thin dmeventd plugin.
|
||||
Use local mempool for raid and mirror plugins.
|
||||
Reworked thread initialization for dmeventd plugins.
|
||||
Dmeventd handles snapshot overflow for now equally as invalid.
|
||||
Convert dmeventd to use common logging macro system from libdm.
|
||||
Return -ENOMEM when device registration fails instead of 0 (=success).
|
||||
Enforce writethrough mode for cleaner policy.
|
||||
Add support for recognition and deactivation of MD devices to blkdeactivate.
|
||||
Move target status functions out of libdm-deptree.
|
||||
Correct use of max_write_behind parameter when generating raid target line.
|
||||
Fix dm-event systemd service to make sure it is executed before mounting.
|
||||
|
||||
Version 1.02.109 - 22nd September 2016
|
||||
======================================
|
||||
Update man pages for dmsetup and dmstats.
|
||||
Improve help text for dmsetup.
|
||||
Use --noflush and --nolockfs when removing device with --force.
|
||||
Parse new Overflow status string for snapshot target.
|
||||
Check dir path components are valid if using dm_create_dir, error out if not.
|
||||
Fix /dev/mapper handling to remove dangling entries if symlinks are found.
|
||||
Make it possible to use blank value as selection for string list report field.
|
||||
|
||||
Version 1.02.108 - 15th September 2015
|
||||
======================================
|
||||
Do not check for full thin pool when activating without messages (1.02.107).
|
||||
|
||||
2
aclocal.m4
vendored
2
aclocal.m4
vendored
@@ -15,7 +15,7 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun
|
||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
# serial 1 (pkg-config-0.24)
|
||||
#
|
||||
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
# Copyright (c) 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -389,8 +389,8 @@ allocation {
|
||||
# This configuration option does not have a default value defined.
|
||||
|
||||
# Configuration section allocation/cache_settings.
|
||||
# Individual settings for policies.
|
||||
# See the help for individual policies for more info.
|
||||
# Settings for the cache policy.
|
||||
# See documentation for individual cache policies for more info.
|
||||
# This configuration section has an automatic default value.
|
||||
# cache_settings {
|
||||
# }
|
||||
@@ -1494,13 +1494,25 @@ activation {
|
||||
# report {
|
||||
|
||||
# Configuration option report/compact_output.
|
||||
# Do not print empty report fields.
|
||||
# Fields that don't have a value set for any of the rows reported are
|
||||
# skipped and not printed. Compact output is applicable only if
|
||||
# report/buffered is enabled.
|
||||
# Do not print empty values for all report fields.
|
||||
# If enabled, all fields that don't have a value set for any of the
|
||||
# rows reported are skipped and not printed. Compact output is
|
||||
# applicable only if report/buffered is enabled. If you need to
|
||||
# compact only specified fields, use compact_output=0 and define
|
||||
# report/compact_output_cols configuration setting instead.
|
||||
# This configuration option has an automatic default value.
|
||||
# compact_output = 0
|
||||
|
||||
# Configuration option report/compact_output_cols.
|
||||
# Do not print empty values for specified report fields.
|
||||
# If defined, specified fields that don't have a value set for any
|
||||
# of the rows reported are skipped and not printed. Compact output
|
||||
# is applicable only if report/buffered is enabled. If you need to
|
||||
# compact all fields, use compact_output=1 instead in which case
|
||||
# the compact_output_cols setting is then ignored.
|
||||
# This configuration option has an automatic default value.
|
||||
# compact_output_cols = ""
|
||||
|
||||
# Configuration option report/aligned.
|
||||
# Align columns in report output.
|
||||
# This configuration option has an automatic default value.
|
||||
|
||||
@@ -154,7 +154,7 @@ static void usage(const char *prog, FILE *file)
|
||||
{
|
||||
fprintf(file, "Usage: %s [options]\n"
|
||||
" -C Sets debug level (from -d) on all clvmd instances clusterwide\n"
|
||||
" -d[n] Set debug logging (0:none, 1:stderr (implies -f option), 2:syslog)\n"
|
||||
" -d[<n>] Set debug logging (0:none, 1:stderr (implies -f option), 2:syslog)\n"
|
||||
" -E<uuid> Take this lock uuid as exclusively locked resource (for restart)\n"
|
||||
" -f Don't fork, run in the foreground\n"
|
||||
" -h Show this help information\n"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
@@ -12,9 +12,9 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "dm-logging.h"
|
||||
#include "dmlib.h"
|
||||
#include "libdevmapper-event.h"
|
||||
//#include "libmultilog.h"
|
||||
#include "dmeventd.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
@@ -23,7 +23,11 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
||||
#include <pthread.h>
|
||||
#include <syslog.h>
|
||||
|
||||
static int _debug_level = 0;
|
||||
static int _use_syslog = 0;
|
||||
static int _sequence_nr = 0;
|
||||
|
||||
struct dm_event_handler {
|
||||
@@ -194,7 +198,7 @@ static int _check_message_id(struct dm_event_daemon_message *msg)
|
||||
if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
|
||||
(pid != getpid()) || (seq_nr != _sequence_nr)) {
|
||||
log_error("Ignoring out-of-sequence reply from dmeventd. "
|
||||
"Expected %d:%d but received %s", getpid(),
|
||||
"Expected %d:%d but received %s.", getpid(),
|
||||
_sequence_nr, msg->data);
|
||||
return 0;
|
||||
}
|
||||
@@ -229,7 +233,7 @@ static int _daemon_read(struct dm_event_fifos *fifos,
|
||||
FD_SET(fifos->server, &fds);
|
||||
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
|
||||
if (ret < 0 && errno != EINTR) {
|
||||
log_error("Unable to read from event server");
|
||||
log_error("Unable to read from event server.");
|
||||
return 0;
|
||||
}
|
||||
if ((ret == 0) && (i > 4) && !bytes) {
|
||||
@@ -295,7 +299,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
log_error("Unable to talk to event daemon");
|
||||
log_error("Unable to talk to event daemon.");
|
||||
return 0;
|
||||
}
|
||||
if (ret == 0)
|
||||
@@ -304,7 +308,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
if (ret < 0) {
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
log_error("Unable to talk to event daemon");
|
||||
log_error("Unable to talk to event daemon.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -316,7 +320,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
FD_SET(fifos->client, &fds);
|
||||
ret = select(fifos->client + 1, NULL, &fds, NULL, NULL);
|
||||
if ((ret < 0) && (errno != EINTR)) {
|
||||
log_error("Unable to talk to event daemon");
|
||||
log_error("Unable to talk to event daemon.");
|
||||
return 0;
|
||||
}
|
||||
} while (ret < 1);
|
||||
@@ -326,7 +330,7 @@ static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
else {
|
||||
log_error("Unable to talk to event daemon");
|
||||
log_error("Unable to talk to event daemon.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -356,7 +360,7 @@ int daemon_talk(struct dm_event_fifos *fifos,
|
||||
getpid(), _sequence_nr,
|
||||
dso_name ? : "-", dev_name ? : "-", evmask, timeout)))
|
||||
< 0) {
|
||||
log_error("_daemon_talk: message allocation failed");
|
||||
log_error("_daemon_talk: message allocation failed.");
|
||||
return -ENOMEM;
|
||||
}
|
||||
msg->cmd = cmd;
|
||||
@@ -444,11 +448,11 @@ static int _start_daemon(char *dmeventd_path, struct dm_event_fifos *fifos)
|
||||
|
||||
else if (!pid) {
|
||||
execvp(args[0], args);
|
||||
log_error("Unable to exec dmeventd: %s", strerror(errno));
|
||||
log_error("Unable to exec dmeventd: %s.", strerror(errno));
|
||||
_exit(EXIT_FAILURE);
|
||||
} else {
|
||||
if (waitpid(pid, &status, 0) < 0)
|
||||
log_error("Unable to start dmeventd: %s",
|
||||
log_error("Unable to start dmeventd: %s.",
|
||||
strerror(errno));
|
||||
else if (WEXITSTATUS(status))
|
||||
log_error("Unable to start dmeventd.");
|
||||
@@ -521,7 +525,7 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
|
||||
struct dm_info info;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
|
||||
log_error("_get_device_info: dm_task creation for info failed");
|
||||
log_error("_get_device_info: dm_task creation for info failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -539,17 +543,17 @@ static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
|
||||
|
||||
/* FIXME Add name or uuid or devno to messages */
|
||||
if (!dm_task_run(dmt)) {
|
||||
log_error("_get_device_info: dm_task_run() failed");
|
||||
log_error("_get_device_info: dm_task_run() failed.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!dm_task_get_info(dmt, &info)) {
|
||||
log_error("_get_device_info: failed to get info for device");
|
||||
log_error("_get_device_info: failed to get info for device.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!info.exists) {
|
||||
log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found",
|
||||
log_error("_get_device_info: %s%s%s%.0d%s%.0d%s%s: device not found.",
|
||||
dmevh->uuid ? : "",
|
||||
(!dmevh->uuid && dmevh->dev_name) ? dmevh->dev_name : "",
|
||||
(!dmevh->uuid && !dmevh->dev_name && dmevh->major > 0) ? "(" : "",
|
||||
@@ -618,12 +622,12 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh)
|
||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2snapshot.so") &&
|
||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2mirror.so") &&
|
||||
!strstr(dmevh->dso, "libdevmapper-event-lvm2raid.so"))
|
||||
log_warn("WARNING: %s: dmeventd plugins are deprecated", dmevh->dso);
|
||||
log_warn("WARNING: %s: dmeventd plugins are deprecated.", dmevh->dso);
|
||||
|
||||
|
||||
if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
|
||||
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
|
||||
log_error("%s: event registration failed: %s",
|
||||
log_error("%s: event registration failed: %s.",
|
||||
dm_task_get_name(dmt),
|
||||
msg.data ? msg.data : strerror(-err));
|
||||
ret = 0;
|
||||
@@ -650,7 +654,7 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
|
||||
|
||||
if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, dmevh->dmeventd_path, &msg,
|
||||
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
|
||||
log_error("%s: event deregistration failed: %s",
|
||||
log_error("%s: event deregistration failed: %s.",
|
||||
dm_task_get_name(dmt),
|
||||
msg.data ? msg.data : strerror(-err));
|
||||
ret = 0;
|
||||
@@ -823,6 +827,79 @@ int dm_event_get_version(struct dm_event_fifos *fifos, int *version) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dm_event_log_set(int debug_level, int use_syslog)
|
||||
{
|
||||
_debug_level = debug_level;
|
||||
_use_syslog = use_syslog;
|
||||
}
|
||||
|
||||
void dm_event_log(const char *subsys, int level, const char *file,
|
||||
int line, int dm_errno_or_class,
|
||||
const char *format, va_list ap)
|
||||
{
|
||||
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static time_t start = 0;
|
||||
const char *indent = "";
|
||||
FILE *stream = stdout;
|
||||
int prio = -1;
|
||||
time_t now;
|
||||
|
||||
switch (level & ~(_LOG_STDERR | _LOG_ONCE)) {
|
||||
case _LOG_DEBUG:
|
||||
if (_debug_level < 3)
|
||||
return;
|
||||
prio = LOG_DEBUG;
|
||||
indent = " ";
|
||||
break;
|
||||
case _LOG_INFO:
|
||||
if (_debug_level < 2)
|
||||
return;
|
||||
prio = LOG_INFO;
|
||||
indent = " ";
|
||||
break;
|
||||
case _LOG_NOTICE:
|
||||
if (_debug_level < 1)
|
||||
return;
|
||||
prio = LOG_NOTICE;
|
||||
indent = " ";
|
||||
break;
|
||||
case _LOG_WARN:
|
||||
prio = LOG_WARNING;
|
||||
break;
|
||||
case _LOG_ERR:
|
||||
prio = LOG_ERR;
|
||||
stream = stderr;
|
||||
break;
|
||||
default:
|
||||
prio = LOG_CRIT;
|
||||
}
|
||||
|
||||
/* Serialize to keep lines readable */
|
||||
pthread_mutex_lock(&_log_mutex);
|
||||
|
||||
if (_use_syslog) {
|
||||
vsyslog(prio, format, ap);
|
||||
} else {
|
||||
now = time(NULL);
|
||||
if (!start)
|
||||
start = now;
|
||||
now -= start;
|
||||
fprintf(stream, "[%2d:%02d] %8x:%-6s%s",
|
||||
(int)now / 60, (int)now % 60,
|
||||
// TODO: Maybe use shorter ID
|
||||
// ((int)(pthread_self()) >> 6) & 0xffff,
|
||||
(int)pthread_self(), subsys,
|
||||
(_debug_level > 3) ? "" : indent);
|
||||
if (_debug_level > 3)
|
||||
fprintf(stream, "%28s:%4d %s", file, line, indent);
|
||||
vfprintf(stream, _(format), ap);
|
||||
fputc('\n', stream);
|
||||
fflush(stream);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_log_mutex);
|
||||
}
|
||||
|
||||
#if 0 /* left out for now */
|
||||
|
||||
static char *_skip_string(char *src, const int delimiter)
|
||||
@@ -856,7 +933,7 @@ int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
|
||||
0, 0))) {
|
||||
char *p = _skip_string(msg.data, ' ');
|
||||
if (!p) {
|
||||
log_error("malformed reply from dmeventd '%s'\n",
|
||||
log_error("Malformed reply from dmeventd '%s'.",
|
||||
msg.data);
|
||||
dm_free(msg.data);
|
||||
return -EIO;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
@@ -105,6 +105,25 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next);
|
||||
int dm_event_register_handler(const struct dm_event_handler *dmevh);
|
||||
int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
|
||||
|
||||
/* Set debug level for logging, and whether to log on stdout/stderr or syslog */
|
||||
void dm_event_log_set(int debug_level, int use_syslog);
|
||||
|
||||
/* Log messages acroding to current debug level */
|
||||
__attribute__((format(printf, 6, 0)))
|
||||
void dm_event_log(const char *subsys, int level, const char *file,
|
||||
int line, int dm_errno_or_class,
|
||||
const char *format, va_list ap);
|
||||
/* Macro to route print_log do dm_event_log() */
|
||||
#define DM_EVENT_LOG_FN(subsys) \
|
||||
void print_log(int level, const char *file, int line, int dm_errno_or_class,\
|
||||
const char *format, ...)\
|
||||
{\
|
||||
va_list ap;\
|
||||
va_start(ap, format);\
|
||||
dm_event_log(subsys, level, file, line, dm_errno_or_class, format, ap);\
|
||||
va_end(ap);\
|
||||
}
|
||||
|
||||
/* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
|
||||
detailed descriptions. */
|
||||
// FIXME misuse of bitmask as enum
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -13,15 +13,11 @@
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "lvm2cmd.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <syslog.h>
|
||||
|
||||
extern int dmeventd_debug;
|
||||
|
||||
/*
|
||||
* register_device() is called first and performs initialisation.
|
||||
@@ -36,48 +32,19 @@ static int _register_count = 0;
|
||||
static struct dm_pool *_mem_pool = NULL;
|
||||
static void *_lvm_handle = NULL;
|
||||
|
||||
DM_EVENT_LOG_FN("lvm")
|
||||
|
||||
static void _lvm2_print_log(int level, const char *file, int line,
|
||||
int dm_errno_or_class, const char *msg)
|
||||
{
|
||||
print_log(level, file, line, dm_errno_or_class, "%s", msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently only one event can be processed at a time.
|
||||
*/
|
||||
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/*
|
||||
* FIXME Do not pass things directly to syslog, rather use the existing logging
|
||||
* facilities to sort logging ... however that mechanism needs to be somehow
|
||||
* configurable and we don't have that option yet
|
||||
*/
|
||||
static void _temporary_log_fn(int level,
|
||||
const char *file __attribute__((unused)),
|
||||
int line __attribute__((unused)),
|
||||
int dm_errno __attribute__((unused)),
|
||||
const char *message)
|
||||
{
|
||||
level &= ~(_LOG_STDERR | _LOG_ONCE);
|
||||
|
||||
switch (level) {
|
||||
case _LOG_DEBUG:
|
||||
if (dmeventd_debug >= 3)
|
||||
syslog(LOG_DEBUG, "%s", message);
|
||||
break;
|
||||
case _LOG_INFO:
|
||||
if (dmeventd_debug >= 2)
|
||||
syslog(LOG_INFO, "%s", message);
|
||||
break;
|
||||
case _LOG_NOTICE:
|
||||
if (dmeventd_debug >= 1)
|
||||
syslog(LOG_NOTICE, "%s", message);
|
||||
break;
|
||||
case _LOG_WARN:
|
||||
syslog(LOG_WARNING, "%s", message);
|
||||
break;
|
||||
case _LOG_ERR:
|
||||
syslog(LOG_ERR, "%s", message);
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_CRIT, "%s", message);
|
||||
}
|
||||
}
|
||||
|
||||
void dmeventd_lvm2_lock(void)
|
||||
{
|
||||
pthread_mutex_lock(&_event_mutex);
|
||||
@@ -95,8 +62,8 @@ int dmeventd_lvm2_init(void)
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
if (!_lvm_handle) {
|
||||
if (!getenv("LVM_LOG_FILE_EPOCH"))
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
lvm2_log_fn(_lvm2_print_log);
|
||||
|
||||
if (!(_lvm_handle = lvm2_init()))
|
||||
goto out;
|
||||
|
||||
@@ -113,6 +80,7 @@ int dmeventd_lvm2_init(void)
|
||||
lvm2_disable_dmeventd_monitoring(_lvm_handle);
|
||||
/* FIXME Temporary: move to dmeventd core */
|
||||
lvm2_run(_lvm_handle, "_memlock_inc");
|
||||
log_debug("lvm plugin initilized.");
|
||||
}
|
||||
|
||||
_register_count++;
|
||||
@@ -128,11 +96,13 @@ void dmeventd_lvm2_exit(void)
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
if (!--_register_count) {
|
||||
log_debug("lvm plugin shuting down.");
|
||||
lvm2_run(_lvm_handle, "_memlock_dec");
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
lvm2_exit(_lvm_handle);
|
||||
_lvm_handle = NULL;
|
||||
log_debug("lvm plugin exited.");
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_register_mutex);
|
||||
@@ -155,8 +125,8 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||
int r;
|
||||
|
||||
if (!dm_split_lvm_name(mem, device, &vg, &lv, &layer)) {
|
||||
syslog(LOG_ERR, "Unable to determine VG name from %s.\n",
|
||||
device);
|
||||
log_error("Unable to determine VG name from %s.",
|
||||
device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -170,7 +140,7 @@ int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||
dm_pool_free(mem, vg);
|
||||
|
||||
if (r < 0) {
|
||||
syslog(LOG_ERR, "Unable to form LVM command. (too long).\n");
|
||||
log_error("Unable to form LVM command. (too long).");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -39,4 +39,36 @@ struct dm_pool *dmeventd_lvm2_pool(void);
|
||||
int dmeventd_lvm2_command(struct dm_pool *mem, char *buffer, size_t size,
|
||||
const char *cmd, const char *device);
|
||||
|
||||
#define dmeventd_lvm2_run_with_lock(cmdline) \
|
||||
({\
|
||||
int rc;\
|
||||
dmeventd_lvm2_lock();\
|
||||
rc = dmeventd_lvm2_run(cmdline);\
|
||||
dmeventd_lvm2_unlock();\
|
||||
rc;\
|
||||
})
|
||||
|
||||
#define dmeventd_lvm2_init_with_pool(name, st) \
|
||||
({\
|
||||
struct dm_pool *mem;\
|
||||
st = NULL;\
|
||||
if (dmeventd_lvm2_init()) {\
|
||||
if ((mem = dm_pool_create(name, 2048)) &&\
|
||||
(st = dm_pool_zalloc(mem, sizeof(*st))))\
|
||||
st->mem = mem;\
|
||||
else {\
|
||||
if (mem)\
|
||||
dm_pool_destroy(mem);\
|
||||
dmeventd_lvm2_exit();\
|
||||
}\
|
||||
}\
|
||||
st;\
|
||||
})
|
||||
|
||||
#define dmeventd_lvm2_exit_with_pool(pool) \
|
||||
do {\
|
||||
dm_pool_destroy(pool->mem);\
|
||||
dmeventd_lvm2_exit();\
|
||||
} while(0)
|
||||
|
||||
#endif /* _DMEVENTD_LVMWRAP_H */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2012 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -13,20 +13,24 @@
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#include "libdevmapper-event.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "defaults.h"
|
||||
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
/* FIXME Missing openlog? */
|
||||
/* FIXME Replace most syslogs with log_error() style messages and add complete context. */
|
||||
/* FIXME Reformat to 80 char lines. */
|
||||
|
||||
#define ME_IGNORE 0
|
||||
#define ME_INSYNC 1
|
||||
#define ME_FAILURE 2
|
||||
|
||||
struct dso_state {
|
||||
struct dm_pool *mem;
|
||||
char cmd_lvscan[512];
|
||||
char cmd_lvconvert[512];
|
||||
};
|
||||
|
||||
DM_EVENT_LOG_FN("mirr")
|
||||
|
||||
static int _process_status_code(const char status_code, const char *dev_name,
|
||||
const char *dev_type, int r)
|
||||
{
|
||||
@@ -39,18 +43,15 @@ static int _process_status_code(const char status_code, const char *dev_name,
|
||||
* U => Unclassified failure (bug)
|
||||
*/
|
||||
if (status_code == 'F') {
|
||||
syslog(LOG_ERR, "%s device %s flush failed.",
|
||||
dev_type, dev_name);
|
||||
log_error("%s device %s flush failed.", dev_type, dev_name);
|
||||
r = ME_FAILURE;
|
||||
} else if (status_code == 'S')
|
||||
syslog(LOG_ERR, "%s device %s sync failed.",
|
||||
dev_type, dev_name);
|
||||
log_error("%s device %s sync failed.", dev_type, dev_name);
|
||||
else if (status_code == 'R')
|
||||
syslog(LOG_ERR, "%s device %s read failed.",
|
||||
dev_type, dev_name);
|
||||
log_error("%s device %s read failed.", dev_type, dev_name);
|
||||
else if (status_code != 'A') {
|
||||
syslog(LOG_ERR, "%s device %s has failed (%c).",
|
||||
dev_type, dev_name, status_code);
|
||||
log_error("%s device %s has failed (%c).",
|
||||
dev_type, dev_name, status_code);
|
||||
r = ME_FAILURE;
|
||||
}
|
||||
|
||||
@@ -125,62 +126,49 @@ out:
|
||||
|
||||
out_parse:
|
||||
dm_free(args);
|
||||
syslog(LOG_ERR, "Unable to parse mirror status string.");
|
||||
log_error("Unable to parse mirror status string.");
|
||||
|
||||
return ME_IGNORE;
|
||||
}
|
||||
|
||||
static int _remove_failed_devices(const char *device)
|
||||
static int _remove_failed_devices(const char *cmd_lvscan, const char *cmd_lvconvert)
|
||||
{
|
||||
int r;
|
||||
#define CMD_SIZE 256 /* FIXME Use system restriction */
|
||||
char cmd_str[CMD_SIZE];
|
||||
|
||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||
"lvscan --cache", device))
|
||||
return -1;
|
||||
|
||||
r = dmeventd_lvm2_run(cmd_str);
|
||||
|
||||
if (!r)
|
||||
syslog(LOG_INFO, "Re-scan of mirror device %s failed.", device);
|
||||
|
||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||
"lvconvert --config devices{ignore_suspended_devices=1} "
|
||||
"--repair --use-policies", device))
|
||||
return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
||||
if (!dmeventd_lvm2_run_with_lock(cmd_lvscan))
|
||||
log_info("Re-scan of mirrored device failed.");
|
||||
|
||||
/* if repair goes OK, report success even if lvscan has failed */
|
||||
r = dmeventd_lvm2_run(cmd_str);
|
||||
r = dmeventd_lvm2_run_with_lock(cmd_lvconvert);
|
||||
|
||||
syslog(LOG_INFO, "Repair of mirrored device %s %s.", device,
|
||||
(r) ? "finished successfully" : "failed");
|
||||
log_info("Repair of mirrored device %s.",
|
||||
(r) ? "finished successfully" : "failed");
|
||||
|
||||
return (r) ? 0 : -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
enum dm_event_mask event __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *user;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
|
||||
dmeventd_lvm2_lock();
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
|
||||
if (!target_type) {
|
||||
syslog(LOG_INFO, "%s mapping lost.", device);
|
||||
log_info("%s mapping lost.", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(target_type, "mirror")) {
|
||||
syslog(LOG_INFO, "%s has unmirrored portion.", device);
|
||||
log_info("%s has unmirrored portion.", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -190,54 +178,75 @@ void process_event(struct dm_task *dmt,
|
||||
_part_ of the device is in sync
|
||||
Also, this is not an error
|
||||
*/
|
||||
syslog(LOG_NOTICE, "%s is now in-sync.", device);
|
||||
log_notice("%s is now in-sync.", device);
|
||||
break;
|
||||
case ME_FAILURE:
|
||||
syslog(LOG_ERR, "Device failure in %s.", device);
|
||||
if (_remove_failed_devices(device))
|
||||
log_error("Device failure in %s.", device);
|
||||
if (!_remove_failed_devices(state->cmd_lvscan,
|
||||
state->cmd_lvconvert))
|
||||
/* FIXME Why are all the error return codes unused? Get rid of them? */
|
||||
syslog(LOG_ERR, "Failed to remove faulty devices in %s.",
|
||||
device);
|
||||
log_error("Failed to remove faulty devices in %s.",
|
||||
device);
|
||||
/* Should check before warning user that device is now linear
|
||||
else
|
||||
syslog(LOG_NOTICE, "%s is now a linear device.\n",
|
||||
device);
|
||||
log_notice("%s is now a linear device.",
|
||||
device);
|
||||
*/
|
||||
break;
|
||||
case ME_IGNORE:
|
||||
break;
|
||||
default:
|
||||
/* FIXME Provide value then! */
|
||||
syslog(LOG_INFO, "Unknown event received.");
|
||||
log_info("Unknown event received.");
|
||||
}
|
||||
} while (next);
|
||||
|
||||
dmeventd_lvm2_unlock();
|
||||
}
|
||||
|
||||
int register_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
if (!dmeventd_lvm2_init())
|
||||
return 0;
|
||||
struct dso_state *state;
|
||||
|
||||
syslog(LOG_INFO, "Monitoring mirror device %s for events.", device);
|
||||
if (!dmeventd_lvm2_init_with_pool("mirror_state", state))
|
||||
goto_bad;
|
||||
|
||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvscan, sizeof(state->cmd_lvscan),
|
||||
"lvscan --cache", device)) {
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
|
||||
"lvconvert --repair --use-policies", device)) {
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
*user = state;
|
||||
|
||||
log_info("Monitoring mirror device %s for events.", device);
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
log_error("Failed to monitor mirror %s.", device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
syslog(LOG_INFO, "No longer monitoring mirror device %s for events.",
|
||||
device);
|
||||
dmeventd_lvm2_exit();
|
||||
struct dso_state *state = *user;
|
||||
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
log_info("No longer monitoring mirror device %s for events.",
|
||||
device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2011 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -13,168 +13,133 @@
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#include "libdevmapper-event.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
|
||||
struct dso_state {
|
||||
struct dm_pool *mem;
|
||||
char cmd_lvscan[512];
|
||||
char cmd_lvconvert[512];
|
||||
int failed;
|
||||
};
|
||||
|
||||
DM_EVENT_LOG_FN("raid")
|
||||
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
/* FIXME Missing openlog? */
|
||||
/* FIXME Replace most syslogs with log_error() style messages and add complete context. */
|
||||
/* FIXME Reformat to 80 char lines. */
|
||||
|
||||
/*
|
||||
* run_repair is a close copy to
|
||||
* plugins/mirror/dmeventd_mirror.c:_remove_failed_devices()
|
||||
*/
|
||||
static int run_repair(const char *device)
|
||||
static int _process_raid_event(struct dso_state *state, char *params, const char *device)
|
||||
{
|
||||
int r;
|
||||
#define CMD_SIZE 256 /* FIXME Use system restriction */
|
||||
char cmd_str[CMD_SIZE];
|
||||
struct dm_status_raid *status;
|
||||
const char *d;
|
||||
|
||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||
"lvscan --cache", device))
|
||||
return -1;
|
||||
|
||||
r = dmeventd_lvm2_run(cmd_str);
|
||||
|
||||
if (!r)
|
||||
syslog(LOG_INFO, "Re-scan of RAID device %s failed.", device);
|
||||
|
||||
if (!dmeventd_lvm2_command(dmeventd_lvm2_pool(), cmd_str, sizeof(cmd_str),
|
||||
"lvconvert --config devices{ignore_suspended_devices=1} "
|
||||
"--repair --use-policies", device))
|
||||
return -1;
|
||||
|
||||
/* if repair goes OK, report success even if lvscan has failed */
|
||||
r = dmeventd_lvm2_run(cmd_str);
|
||||
|
||||
if (!r)
|
||||
syslog(LOG_INFO, "Repair of RAID device %s failed.", device);
|
||||
|
||||
return (r) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int _process_raid_event(char *params, const char *device)
|
||||
{
|
||||
int i, n, failure = 0;
|
||||
char *p, *a[4];
|
||||
char *raid_type;
|
||||
char *num_devices;
|
||||
char *health_chars;
|
||||
char *resync_ratio;
|
||||
|
||||
/*
|
||||
* RAID parms: <raid_type> <#raid_disks> \
|
||||
* <health chars> <resync ratio>
|
||||
*/
|
||||
if (!dm_split_words(params, 4, 0, a)) {
|
||||
syslog(LOG_ERR, "Failed to process status line for %s\n",
|
||||
device);
|
||||
return -EINVAL;
|
||||
}
|
||||
raid_type = a[0];
|
||||
num_devices = a[1];
|
||||
health_chars = a[2];
|
||||
resync_ratio = a[3];
|
||||
|
||||
if (!(n = atoi(num_devices))) {
|
||||
syslog(LOG_ERR, "Failed to parse number of devices for %s: %s",
|
||||
device, num_devices);
|
||||
return -EINVAL;
|
||||
if (!dm_get_status_raid(state->mem, params, &status)) {
|
||||
log_error("Failed to process status line for %s.", device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
switch (health_chars[i]) {
|
||||
case 'A':
|
||||
/* Device is 'A'live and well */
|
||||
case 'a':
|
||||
/* Device is 'a'live, but not yet in-sync */
|
||||
break;
|
||||
case 'D':
|
||||
syslog(LOG_ERR,
|
||||
"Device #%d of %s array, %s, has failed.",
|
||||
i, raid_type, device);
|
||||
failure++;
|
||||
break;
|
||||
default:
|
||||
/* Unhandled character returned from kernel */
|
||||
break;
|
||||
if ((d = strchr(status->dev_health, 'D'))) {
|
||||
if (state->failed)
|
||||
goto out; /* already reported */
|
||||
|
||||
log_error("Device #%d of %s array, %s, has failed.",
|
||||
(int)(d - status->dev_health),
|
||||
status->raid_type, device);
|
||||
|
||||
state->failed = 1;
|
||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvscan))
|
||||
log_warn("WARNING: Re-scan of RAID device %s failed.", device);
|
||||
|
||||
/* if repair goes OK, report success even if lvscan has failed */
|
||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_lvconvert)) {
|
||||
log_info("Repair of RAID device %s failed.", device);
|
||||
dm_pool_free(state->mem, status);
|
||||
return 0;
|
||||
}
|
||||
if (failure)
|
||||
return run_repair(device);
|
||||
} else {
|
||||
state->failed = 0;
|
||||
log_info("%s array, %s, is %s in-sync.",
|
||||
status->raid_type, device,
|
||||
(status->insync_regions == status->total_regions) ? "now" : "not");
|
||||
}
|
||||
out:
|
||||
dm_pool_free(state->mem, status);
|
||||
|
||||
p = strstr(resync_ratio, "/");
|
||||
if (!p) {
|
||||
syslog(LOG_ERR, "Failed to parse resync_ratio for %s: %s",
|
||||
device, resync_ratio);
|
||||
return -EINVAL;
|
||||
}
|
||||
p[0] = '\0';
|
||||
syslog(LOG_INFO, "%s array, %s, is %s in-sync.",
|
||||
raid_type, device, strcmp(resync_ratio, p+1) ? "not" : "now");
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
enum dm_event_mask event __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *user;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
|
||||
dmeventd_lvm2_lock();
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
|
||||
if (!target_type) {
|
||||
syslog(LOG_INFO, "%s mapping lost.", device);
|
||||
log_info("%s mapping lost.", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(target_type, "raid")) {
|
||||
syslog(LOG_INFO, "%s has non-raid portion.", device);
|
||||
log_info("%s has non-raid portion.", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_process_raid_event(params, device))
|
||||
syslog(LOG_ERR, "Failed to process event for %s",
|
||||
device);
|
||||
if (!_process_raid_event(state, params, device))
|
||||
log_error("Failed to process event for %s.",
|
||||
device);
|
||||
} while (next);
|
||||
|
||||
dmeventd_lvm2_unlock();
|
||||
}
|
||||
|
||||
int register_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
if (!dmeventd_lvm2_init())
|
||||
return 0;
|
||||
struct dso_state *state;
|
||||
|
||||
syslog(LOG_INFO, "Monitoring RAID device %s for events.", device);
|
||||
if (!dmeventd_lvm2_init_with_pool("raid_state", state))
|
||||
goto_bad;
|
||||
|
||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvscan, sizeof(state->cmd_lvscan),
|
||||
"lvscan --cache", device) ||
|
||||
!dmeventd_lvm2_command(state->mem, state->cmd_lvconvert, sizeof(state->cmd_lvconvert),
|
||||
"lvconvert --config devices{ignore_suspended_devices=1} "
|
||||
"--repair --use-policies", device)) {
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
*user = state;
|
||||
|
||||
log_info("Monitoring RAID device %s for events.", device);
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
log_error("Failed to monitor RAID %s.", device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **unused __attribute__((unused)))
|
||||
void **user)
|
||||
{
|
||||
syslog(LOG_INFO, "No longer monitoring RAID device %s for events.",
|
||||
device);
|
||||
dmeventd_lvm2_exit();
|
||||
struct dso_state *state = *user;
|
||||
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
log_info("No longer monitoring RAID device %s for events.",
|
||||
device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2011 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2007-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -13,31 +13,31 @@
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#include "libdevmapper-event.h"
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
#include <stdarg.h>
|
||||
/* FIXME Missing openlog? */
|
||||
#include <pthread.h>
|
||||
|
||||
/* First warning when snapshot is 80% full. */
|
||||
#define WARNING_THRESH 80
|
||||
#define WARNING_THRESH (DM_PERCENT_1 * 80)
|
||||
/* Run a check every 5%. */
|
||||
#define CHECK_STEP 5
|
||||
#define CHECK_STEP (DM_PERCENT_1 * 5)
|
||||
/* Do not bother checking snapshots less than 50% full. */
|
||||
#define CHECK_MINIMUM 50
|
||||
#define CHECK_MINIMUM (DM_PERCENT_1 * 50)
|
||||
|
||||
#define UMOUNT_COMMAND "/bin/umount"
|
||||
|
||||
struct dso_state {
|
||||
struct dm_pool *mem;
|
||||
int percent_check;
|
||||
dm_percent_t percent_check;
|
||||
uint64_t known_size;
|
||||
char cmd_str[1024];
|
||||
char cmd_lvextend[512];
|
||||
};
|
||||
|
||||
DM_EVENT_LOG_FN("snap")
|
||||
|
||||
static int _run(const char *cmd, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -62,7 +62,7 @@ static int _run(const char *cmd, ...)
|
||||
va_end(ap);
|
||||
|
||||
execvp(cmd, (char **)argv);
|
||||
syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno));
|
||||
log_sys_error("exec", cmd);
|
||||
exit(127);
|
||||
}
|
||||
|
||||
@@ -81,18 +81,56 @@ static int _run(const char *cmd, ...)
|
||||
|
||||
static int _extend(const char *cmd)
|
||||
{
|
||||
return dmeventd_lvm2_run(cmd);
|
||||
log_debug("Extending snapshot via %s.", cmd);
|
||||
return dmeventd_lvm2_run_with_lock(cmd);
|
||||
}
|
||||
|
||||
#ifdef SNAPSHOT_REMOVE
|
||||
/* Remove invalid snapshot from dm-table */
|
||||
/* Experimental for now and not used by default */
|
||||
static int _remove(const char *uuid)
|
||||
{
|
||||
int r = 1;
|
||||
uint32_t cookie = 0;
|
||||
struct dm_task *dmt;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
|
||||
return 0;
|
||||
|
||||
if (!dm_task_set_uuid(dmt, uuid)) {
|
||||
r = 0;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
dm_task_retry_remove(dmt);
|
||||
|
||||
if (!dm_task_set_cookie(dmt, &cookie, 0)) {
|
||||
r = 0;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
r = 0;
|
||||
goto_out;
|
||||
}
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif /* SNAPSHOT_REMOVE */
|
||||
|
||||
static void _umount(const char *device, int major, int minor)
|
||||
{
|
||||
FILE *mounts;
|
||||
char buffer[4096];
|
||||
char *words[3];
|
||||
struct stat st;
|
||||
const char procmounts[] = "/proc/mounts";
|
||||
|
||||
if (!(mounts = fopen("/proc/mounts", "r"))) {
|
||||
syslog(LOG_ERR, "Could not read /proc/mounts. Not umounting %s.\n", device);
|
||||
if (!(mounts = fopen(procmounts, "r"))) {
|
||||
log_sys_error("fopen", procmounts);
|
||||
log_error("Not umounting %s.", device);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -112,21 +150,22 @@ static void _umount(const char *device, int major, int minor)
|
||||
if (S_ISBLK(st.st_mode) &&
|
||||
major(st.st_rdev) == major &&
|
||||
minor(st.st_rdev) == minor) {
|
||||
syslog(LOG_ERR, "Unmounting invalid snapshot %s from %s.\n", device, words[1]);
|
||||
if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
|
||||
syslog(LOG_ERR, "Failed to umount snapshot %s from %s: %s.\n",
|
||||
device, words[1], strerror(errno));
|
||||
log_error("Unmounting invalid snapshot %s from %s.", device, words[1]);
|
||||
if (!_run(UMOUNT_COMMAND, "-fl", words[1], NULL))
|
||||
log_error("Failed to umount snapshot %s from %s: %s.",
|
||||
device, words[1], strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (fclose(mounts))
|
||||
syslog(LOG_ERR, "Failed to close /proc/mounts.\n");
|
||||
log_sys_error("close", procmounts);
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
enum dm_event_mask event __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *user;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
@@ -134,28 +173,47 @@ void process_event(struct dm_task *dmt,
|
||||
struct dm_status_snapshot *status = NULL;
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
int percent;
|
||||
struct dso_state *state = *private;
|
||||
struct dm_info info;
|
||||
|
||||
/* No longer monitoring, waiting for remove */
|
||||
if (!state->percent_check)
|
||||
return;
|
||||
|
||||
dmeventd_lvm2_lock();
|
||||
|
||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
if (!target_type)
|
||||
goto out;
|
||||
if (!target_type || strcmp(target_type, "snapshot")) {
|
||||
log_error("Target %s is not snapshot.", target_type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dm_get_status_snapshot(state->mem, params, &status))
|
||||
goto out;
|
||||
if (!dm_get_status_snapshot(state->mem, params, &status)) {
|
||||
log_error("Cannot parse snapshot %s state: %s.", device, params);
|
||||
return;
|
||||
}
|
||||
|
||||
if (status->invalid) {
|
||||
struct dm_info info;
|
||||
if (dm_task_get_info(dmt, &info)) {
|
||||
dmeventd_lvm2_unlock();
|
||||
/*
|
||||
* If the snapshot has been invalidated or we failed to parse
|
||||
* the status string. Report the full status string to syslog.
|
||||
*/
|
||||
if (status->invalid || status->overflow || !status->total_sectors) {
|
||||
log_warn("WARNING: Snapshot %s changed state to: %s and should be removed.",
|
||||
device, params);
|
||||
state->percent_check = 0;
|
||||
if (dm_task_get_info(dmt, &info))
|
||||
_umount(device, info.major, info.minor);
|
||||
return;
|
||||
} /* else; too bad, but this is best-effort thing... */
|
||||
#ifdef SNAPSHOT_REMOVE
|
||||
/* Maybe configurable ? */
|
||||
_remove(dm_task_get_uuid(dmt));
|
||||
#endif
|
||||
pthread_kill(pthread_self(), SIGALRM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (length <= (status->used_sectors - status->metadata_sectors)) {
|
||||
/* TODO eventually recognize earlier when room is enough */
|
||||
log_info("Dropping monitoring of fully provisioned snapshot %s.",
|
||||
device);
|
||||
pthread_kill(pthread_self(), SIGALRM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Snapshot size had changed. Clear the threshold. */
|
||||
@@ -164,69 +222,50 @@ void process_event(struct dm_task *dmt,
|
||||
state->known_size = status->total_sectors;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the snapshot has been invalidated or we failed to parse
|
||||
* the status string. Report the full status string to syslog.
|
||||
*/
|
||||
if (status->invalid || !status->total_sectors) {
|
||||
syslog(LOG_ERR, "Snapshot %s changed state to: %s\n", device, params);
|
||||
state->percent_check = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
percent = (int) (100 * status->used_sectors / status->total_sectors);
|
||||
percent = dm_make_percent(status->used_sectors, status->total_sectors);
|
||||
if (percent >= state->percent_check) {
|
||||
/* Usage has raised more than CHECK_STEP since the last
|
||||
time. Run actions. */
|
||||
state->percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
|
||||
|
||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||
syslog(LOG_WARNING, "Snapshot %s is now %i%% full.\n", device, percent);
|
||||
/* Try to extend the snapshot, in accord with user-set policies */
|
||||
if (!_extend(state->cmd_str))
|
||||
syslog(LOG_ERR, "Failed to extend snapshot %s.\n", device);
|
||||
}
|
||||
log_warn("WARNING: Snapshot %s is now %.2f%% full.",
|
||||
device, dm_percent_to_float(percent));
|
||||
|
||||
/* Try to extend the snapshot, in accord with user-set policies */
|
||||
if (!_extend(state->cmd_lvextend))
|
||||
log_error("Failed to extend snapshot %s.", device);
|
||||
}
|
||||
out:
|
||||
if (status)
|
||||
dm_pool_free(state->mem, status);
|
||||
dmeventd_lvm2_unlock();
|
||||
dm_pool_free(state->mem, status);
|
||||
}
|
||||
|
||||
int register_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dm_pool *statemem = NULL;
|
||||
struct dso_state *state;
|
||||
|
||||
if (!dmeventd_lvm2_init())
|
||||
goto out;
|
||||
if (!dmeventd_lvm2_init_with_pool("snapshot_state", state))
|
||||
goto_bad;
|
||||
|
||||
if (!(statemem = dm_pool_create("snapshot_state", 512)) ||
|
||||
!(state = dm_pool_zalloc(statemem, sizeof(*state))))
|
||||
goto bad;
|
||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_lvextend,
|
||||
sizeof(state->cmd_lvextend),
|
||||
"lvextend --use-policies", device)) {
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (!dmeventd_lvm2_command(statemem, state->cmd_str,
|
||||
sizeof(state->cmd_str),
|
||||
"lvextend --use-policies", device))
|
||||
goto bad;
|
||||
|
||||
state->mem = statemem;
|
||||
state->percent_check = CHECK_MINIMUM;
|
||||
*private = state;
|
||||
*user = state;
|
||||
|
||||
syslog(LOG_INFO, "Monitoring snapshot %s\n", device);
|
||||
log_info("Monitoring snapshot %s.", device);
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
if (statemem)
|
||||
dm_pool_destroy(statemem);
|
||||
dmeventd_lvm2_exit();
|
||||
out:
|
||||
syslog(LOG_ERR, "Failed to monitor snapshot %s.\n", device);
|
||||
log_error("Failed to monitor snapshot %s.", device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -235,13 +274,12 @@ int unregister_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *private;
|
||||
struct dso_state *state = *user;
|
||||
|
||||
syslog(LOG_INFO, "No longer monitoring snapshot %s\n", device);
|
||||
dm_pool_destroy(state->mem);
|
||||
dmeventd_lvm2_exit();
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
log_info("No longer monitoring snapshot %s.", device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -12,25 +12,33 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lib.h" /* using here lvm log */
|
||||
#include "dmeventd_lvm.h"
|
||||
#include "libdevmapper-event.h"
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
#include <stdarg.h>
|
||||
/* FIXME Missing openlog? */
|
||||
#include <pthread.h>
|
||||
|
||||
/* First warning when thin is 80% full. */
|
||||
#define WARNING_THRESH 80
|
||||
/* TODO - move this mountinfo code into library to be reusable */
|
||||
#ifdef __linux__
|
||||
# include "kdev_t.h"
|
||||
#else
|
||||
# define MAJOR(x) major((x))
|
||||
# define MINOR(x) minor((x))
|
||||
#endif
|
||||
|
||||
/* First warning when thin data or metadata is 80% full. */
|
||||
#define WARNING_THRESH (DM_PERCENT_1 * 80)
|
||||
/* Run a check every 5%. */
|
||||
#define CHECK_STEP 5
|
||||
/* Do not bother checking thins less than 50% full. */
|
||||
#define CHECK_MINIMUM 50
|
||||
#define CHECK_STEP (DM_PERCENT_1 * 5)
|
||||
/* Do not bother checking thin data or metadata is less than 50% full. */
|
||||
#define CHECK_MINIMUM (DM_PERCENT_1 * 50)
|
||||
|
||||
#define UMOUNT_COMMAND "/bin/umount"
|
||||
|
||||
#define MAX_FAILS (10)
|
||||
|
||||
#define THIN_DEBUG 0
|
||||
|
||||
struct dso_state {
|
||||
@@ -39,18 +47,11 @@ struct dso_state {
|
||||
int data_percent_check;
|
||||
uint64_t known_metadata_size;
|
||||
uint64_t known_data_size;
|
||||
unsigned fails;
|
||||
char cmd_str[1024];
|
||||
};
|
||||
|
||||
|
||||
/* TODO - move this mountinfo code into library to be reusable */
|
||||
#ifdef __linux__
|
||||
# include "kdev_t.h"
|
||||
#else
|
||||
# define MAJOR(x) major((x))
|
||||
# define MINOR(x) minor((x))
|
||||
# define MKDEV(x,y) makedev((x),(y))
|
||||
#endif
|
||||
DM_EVENT_LOG_FN("thin")
|
||||
|
||||
/* Get dependencies for device, and try to find matching device */
|
||||
static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_minor)
|
||||
@@ -93,8 +94,8 @@ static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_mino
|
||||
{
|
||||
char dev_name[PATH_MAX];
|
||||
if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name)))
|
||||
syslog(LOG_DEBUG, "Found %s (%u:%u) depends on %s",
|
||||
name, major, *dev_minor, dev_name);
|
||||
log_debug("Found %s (%u:%u) depends on %s.",
|
||||
name, major, *dev_minor, dev_name);
|
||||
}
|
||||
#endif
|
||||
r = 1;
|
||||
@@ -141,14 +142,6 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _extend(struct dso_state *state)
|
||||
{
|
||||
#if THIN_DEBUG
|
||||
syslog(LOG_INFO, "dmeventd executes: %s.\n", state->cmd_str);
|
||||
#endif
|
||||
return dmeventd_lvm2_run(state->cmd_str);
|
||||
}
|
||||
|
||||
static int _run(const char *cmd, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -168,12 +161,12 @@ static int _run(const char *cmd, ...)
|
||||
argv = alloca(sizeof(const char *) * (argc + 1));
|
||||
|
||||
argv[0] = cmd;
|
||||
va_start(ap, cmd);
|
||||
va_start(ap, cmd);
|
||||
while ((argv[++i] = va_arg(ap, const char *)));
|
||||
va_end(ap);
|
||||
|
||||
execvp(cmd, (char **)argv);
|
||||
syslog(LOG_ERR, "Failed to execute %s: %s.\n", cmd, strerror(errno));
|
||||
log_sys_error("exec", cmd);
|
||||
exit(127);
|
||||
}
|
||||
|
||||
@@ -191,9 +184,9 @@ static int _run(const char *cmd, ...)
|
||||
}
|
||||
|
||||
struct mountinfo_s {
|
||||
const char *device;
|
||||
struct dm_info info;
|
||||
dm_bitset_t minors; /* Bitset for active thin pool minors */
|
||||
const char *device;
|
||||
};
|
||||
|
||||
static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
||||
@@ -202,11 +195,11 @@ static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
||||
struct mountinfo_s *data = cb_data;
|
||||
|
||||
if ((major == data->info.major) && dm_bit(data->minors, minor)) {
|
||||
syslog(LOG_INFO, "Unmounting thin volume %s from %s.\n",
|
||||
data->device, target);
|
||||
log_info("Unmounting thin volume %s from %s.",
|
||||
data->device, target);
|
||||
if (!_run(UMOUNT_COMMAND, "-fl", target, NULL))
|
||||
syslog(LOG_ERR, "Failed to umount thin %s from %s: %s.\n",
|
||||
data->device, target, strerror(errno));
|
||||
log_error("Failed to umount thin %s from %s: %s.",
|
||||
data->device, target, strerror(errno));
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -216,78 +209,94 @@ static int _umount_device(char *buffer, unsigned major, unsigned minor,
|
||||
* Find all thin pool users and try to umount them.
|
||||
* TODO: work with read-only thin pool support
|
||||
*/
|
||||
static void _umount(struct dm_task *dmt, const char *device)
|
||||
static void _umount(struct dm_task *dmt)
|
||||
{
|
||||
/* TODO: Convert to use hash to reduce memory usage */
|
||||
static const size_t MINORS = (1U << 20); /* 20 bit */
|
||||
struct mountinfo_s data = {
|
||||
.device = device,
|
||||
};
|
||||
struct mountinfo_s data = { NULL };
|
||||
|
||||
if (!dm_task_get_info(dmt, &data.info))
|
||||
return;
|
||||
|
||||
dmeventd_lvm2_unlock();
|
||||
data.device = dm_task_get_name(dmt);
|
||||
|
||||
if (!(data.minors = dm_bitset_create(NULL, MINORS))) {
|
||||
syslog(LOG_ERR, "Failed to allocate bitset. Not unmounting %s.\n", device);
|
||||
log_error("Failed to allocate bitset. Not unmounting %s.", data.device);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!_find_all_devs(data.minors, data.info.major, data.info.minor)) {
|
||||
syslog(LOG_ERR, "Failed to detect mounted volumes for %s.\n", device);
|
||||
log_error("Failed to detect mounted volumes for %s.", data.device);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dm_mountinfo_read(_umount_device, &data)) {
|
||||
syslog(LOG_ERR, "Could not parse mountinfo file.\n");
|
||||
log_error("Could not parse mountinfo file.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (data.minors)
|
||||
dm_bitset_destroy(data.minors);
|
||||
dmeventd_lvm2_lock();
|
||||
}
|
||||
|
||||
static void _use_policy(struct dm_task *dmt, struct dso_state *state)
|
||||
{
|
||||
#if THIN_DEBUG
|
||||
log_info("dmeventd executes: %s.", state->cmd_str);
|
||||
#endif
|
||||
if (!dmeventd_lvm2_run_with_lock(state->cmd_str)) {
|
||||
log_error("Failed to extend thin pool %s.",
|
||||
dm_task_get_name(dmt));
|
||||
_umount(dmt);
|
||||
state->fails++;
|
||||
} else
|
||||
state->fails = 0;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt,
|
||||
enum dm_event_mask event __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
int percent;
|
||||
struct dso_state *state = *private;
|
||||
struct dso_state *state = *user;
|
||||
struct dm_status_thin_pool *tps = NULL;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
int needs_policy = 0;
|
||||
|
||||
#if 0
|
||||
/* No longer monitoring, waiting for remove */
|
||||
if (!state->meta_percent_check && !state->data_percent_check)
|
||||
return;
|
||||
#endif
|
||||
dmeventd_lvm2_lock();
|
||||
if (event & DM_EVENT_DEVICE_ERROR) {
|
||||
/* Error -> no need to check and do instant resize */
|
||||
_use_policy(dmt, state);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
|
||||
if (!target_type || (strcmp(target_type, "thin-pool") != 0)) {
|
||||
syslog(LOG_ERR, "Invalid target type.\n");
|
||||
log_error("Invalid target type.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dm_get_status_thin_pool(state->mem, params, &tps)) {
|
||||
syslog(LOG_ERR, "Failed to parse status.\n");
|
||||
_umount(dmt, device);
|
||||
log_error("Failed to parse status.");
|
||||
_umount(dmt);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if THIN_DEBUG
|
||||
syslog(LOG_INFO, "%p: Got status %" PRIu64 " / %" PRIu64
|
||||
" %" PRIu64 " / %" PRIu64 ".\n", state,
|
||||
tps->used_metadata_blocks, tps->total_metadata_blocks,
|
||||
tps->used_data_blocks, tps->total_data_blocks);
|
||||
log_debug("Thin pool status " FMTu64 "/" FMTu64 " "
|
||||
FMTu64 "/" FMTu64 ".",
|
||||
tps->used_metadata_blocks, tps->total_metadata_blocks,
|
||||
tps->used_data_blocks, tps->total_data_blocks);
|
||||
#endif
|
||||
|
||||
/* Thin pool size had changed. Clear the threshold. */
|
||||
@@ -301,7 +310,7 @@ void process_event(struct dm_task *dmt,
|
||||
state->known_data_size = tps->total_data_blocks;
|
||||
}
|
||||
|
||||
percent = 100 * tps->used_metadata_blocks / tps->total_metadata_blocks;
|
||||
percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
|
||||
if (percent >= state->metadata_percent_check) {
|
||||
/*
|
||||
* Usage has raised more than CHECK_STEP since the last
|
||||
@@ -311,18 +320,12 @@ void process_event(struct dm_task *dmt,
|
||||
|
||||
/* FIXME: extension of metadata needs to be written! */
|
||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||
syslog(LOG_WARNING, "Thin metadata %s is now %i%% full.\n",
|
||||
device, percent);
|
||||
/* Try to extend the metadata, in accord with user-set policies */
|
||||
if (!_extend(state)) {
|
||||
syslog(LOG_ERR, "Failed to extend thin metadata %s.\n",
|
||||
device);
|
||||
_umount(dmt, device);
|
||||
}
|
||||
/* FIXME: hmm READ-ONLY switch should happen in error path */
|
||||
log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
|
||||
device, dm_percent_to_float(percent));
|
||||
needs_policy = 1;
|
||||
}
|
||||
|
||||
percent = 100 * tps->used_data_blocks / tps->total_data_blocks;
|
||||
percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
|
||||
if (percent >= state->data_percent_check) {
|
||||
/*
|
||||
* Usage has raised more than CHECK_STEP since
|
||||
@@ -331,56 +334,53 @@ void process_event(struct dm_task *dmt,
|
||||
state->data_percent_check = (percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
|
||||
|
||||
if (percent >= WARNING_THRESH) /* Print a warning to syslog. */
|
||||
syslog(LOG_WARNING, "Thin %s is now %i%% full.\n", device, percent);
|
||||
/* Try to extend the thin data, in accord with user-set policies */
|
||||
if (!_extend(state)) {
|
||||
syslog(LOG_ERR, "Failed to extend thin %s.\n", device);
|
||||
state->data_percent_check = 0;
|
||||
_umount(dmt, device);
|
||||
}
|
||||
/* FIXME: hmm READ-ONLY switch should happen in error path */
|
||||
log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
|
||||
device, dm_percent_to_float(percent));
|
||||
needs_policy = 1;
|
||||
}
|
||||
|
||||
if (needs_policy)
|
||||
_use_policy(dmt, state);
|
||||
out:
|
||||
if (tps)
|
||||
dm_pool_free(state->mem, tps);
|
||||
|
||||
dmeventd_lvm2_unlock();
|
||||
if (state->fails >= MAX_FAILS) {
|
||||
log_warn("WARNING: Dropping monitoring of %s. "
|
||||
"lvm2 command fails too often (%u times in raw).",
|
||||
device, state->fails);
|
||||
pthread_kill(pthread_self(), SIGALRM);
|
||||
}
|
||||
}
|
||||
|
||||
int register_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dm_pool *statemem = NULL;
|
||||
struct dso_state *state;
|
||||
|
||||
if (!dmeventd_lvm2_init())
|
||||
goto bad;
|
||||
if (!dmeventd_lvm2_init_with_pool("thin_pool_state", state))
|
||||
goto_bad;
|
||||
|
||||
if (!(statemem = dm_pool_create("thin_pool_state", 2048)) ||
|
||||
!(state = dm_pool_zalloc(statemem, sizeof(*state))) ||
|
||||
!dmeventd_lvm2_command(statemem, state->cmd_str,
|
||||
if (!dmeventd_lvm2_command(state->mem, state->cmd_str,
|
||||
sizeof(state->cmd_str),
|
||||
"lvextend --use-policies",
|
||||
device)) {
|
||||
if (statemem)
|
||||
dm_pool_destroy(statemem);
|
||||
dmeventd_lvm2_exit();
|
||||
goto bad;
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
state->mem = statemem;
|
||||
state->metadata_percent_check = CHECK_MINIMUM;
|
||||
state->data_percent_check = CHECK_MINIMUM;
|
||||
*private = state;
|
||||
*user = state;
|
||||
|
||||
syslog(LOG_INFO, "Monitoring thin %s.\n", device);
|
||||
log_info("Monitoring thin %s.", device);
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
syslog(LOG_ERR, "Failed to monitor thin %s.\n", device);
|
||||
log_error("Failed to monitor thin %s.", device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -389,13 +389,12 @@ int unregister_device(const char *device,
|
||||
const char *uuid __attribute__((unused)),
|
||||
int major __attribute__((unused)),
|
||||
int minor __attribute__((unused)),
|
||||
void **private)
|
||||
void **user)
|
||||
{
|
||||
struct dso_state *state = *private;
|
||||
struct dso_state *state = *user;
|
||||
|
||||
syslog(LOG_INFO, "No longer monitoring thin %s.\n", device);
|
||||
dm_pool_destroy(state->mem);
|
||||
dmeventd_lvm2_exit();
|
||||
dmeventd_lvm2_exit_with_pool(state);
|
||||
log_info("No longer monitoring thin %s.", device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012-2015 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "lvm-version.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
|
||||
@@ -123,6 +124,7 @@ struct vg_info {
|
||||
#define VGFL_INVALID 0x00000001
|
||||
|
||||
typedef struct {
|
||||
daemon_idle *idle;
|
||||
log_state *log; /* convenience */
|
||||
const char *log_config;
|
||||
|
||||
@@ -1592,6 +1594,9 @@ static int init(daemon_state *s)
|
||||
/* if (ls->initial_registrations)
|
||||
_process_initial_registrations(ds->initial_registrations); */
|
||||
|
||||
if (ls->idle)
|
||||
ls->idle->is_idle = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1614,21 +1619,39 @@ static int fini(daemon_state *s)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int process_timeout_arg(const char *str, unsigned *max_timeouts)
|
||||
{
|
||||
char *endptr;
|
||||
unsigned long l;
|
||||
|
||||
errno = 0;
|
||||
l = strtoul(str, &endptr, 10);
|
||||
if (errno || *endptr || l >= UINT_MAX)
|
||||
return 0;
|
||||
|
||||
*max_timeouts = (unsigned) l;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void usage(const char *prog, FILE *file)
|
||||
{
|
||||
fprintf(file, "Usage:\n"
|
||||
"%s [-V] [-h] [-f] [-l {all|wire|debug}] [-s path]\n\n"
|
||||
"%s [-V] [-h] [-f] [-l level[,level ...]] [-s path] [-t secs]\n\n"
|
||||
" -V Show version of lvmetad\n"
|
||||
" -h Show this help information\n"
|
||||
" -f Don't fork, run in the foreground\n"
|
||||
" -l Logging message level (-l {all|wire|debug})\n"
|
||||
" -l Logging message levels (all,fatal,error,warn,info,wire,debug)\n"
|
||||
" -p Set path to the pidfile\n"
|
||||
" -s Set path to the socket to listen on\n\n", prog);
|
||||
" -s Set path to the socket to listen on\n"
|
||||
" -t Time to wait in seconds before shutdown on idle (missing or 0 = inifinite)\n\n", prog);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
signed char opt;
|
||||
struct timeval timeout;
|
||||
daemon_idle di = { .ptimeout = &timeout };
|
||||
lvmetad_state ls = { .log_config = "" };
|
||||
daemon_state s = {
|
||||
.daemon_fini = fini,
|
||||
@@ -1643,7 +1666,7 @@ int main(int argc, char *argv[])
|
||||
};
|
||||
|
||||
// use getopt_long
|
||||
while ((opt = getopt(argc, argv, "?fhVl:p:s:")) != EOF) {
|
||||
while ((opt = getopt(argc, argv, "?fhVl:p:s:t:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
usage(argv[0], stdout);
|
||||
@@ -1663,6 +1686,15 @@ int main(int argc, char *argv[])
|
||||
case 's': // --socket
|
||||
s.socket_path = optarg;
|
||||
break;
|
||||
case 't':
|
||||
if (!process_timeout_arg(optarg, &di.max_timeouts)) {
|
||||
fprintf(stderr, "Invalid value of timeout parameter.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* 0 equals to wait indefinitely */
|
||||
if (di.max_timeouts)
|
||||
s.idle = ls.idle = &di;
|
||||
break;
|
||||
case 'V':
|
||||
printf("lvmetad version: " LVM_VERSION "\n");
|
||||
exit(1);
|
||||
|
||||
@@ -1031,10 +1031,12 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
|
||||
|
||||
memset(&vb, 0, sizeof(vb));
|
||||
|
||||
r->last_client_id = act->client_id;
|
||||
|
||||
if (r->type == LD_RT_LV)
|
||||
log_debug("S %s R %s res_lock mode %s (%s)", ls->name, r->name, mode_str(act->mode), act->lv_name);
|
||||
log_debug("S %s R %s res_lock cl %u mode %s (%s)", ls->name, r->name, act->client_id, mode_str(act->mode), act->lv_name);
|
||||
else
|
||||
log_debug("S %s R %s res_lock mode %s", ls->name, r->name, mode_str(act->mode));
|
||||
log_debug("S %s R %s res_lock cl %u mode %s", ls->name, r->name, act->client_id, mode_str(act->mode));
|
||||
|
||||
if (r->mode == LD_LK_SH && act->mode == LD_LK_SH)
|
||||
goto add_lk;
|
||||
@@ -1045,10 +1047,10 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
|
||||
rv = lm_lock(ls, r, act->mode, act, &vb, retry, act->flags & LD_AF_ADOPT);
|
||||
|
||||
if (r->use_vb)
|
||||
log_debug("S %s R %s res_lock %d read vb %x %x %u",
|
||||
log_debug("S %s R %s res_lock rv %d read vb %x %x %u",
|
||||
ls->name, r->name, rv, vb.version, vb.flags, vb.r_version);
|
||||
else
|
||||
log_debug("S %s R %s res_lock %d", ls->name, r->name, rv);
|
||||
log_debug("S %s R %s res_lock rv %d", ls->name, r->name, rv);
|
||||
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
@@ -1298,6 +1300,26 @@ add_lk:
|
||||
lk->client_id = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* LV_LOCK means the action acquired the lv lock in the lock manager
|
||||
* (as opposed to finding that the lv lock was already held). If
|
||||
* the client for this LV_LOCK action fails before we send the result,
|
||||
* then we automatically unlock the lv since the lv wasn't activated.
|
||||
* (There will always be an odd chance the lv lock is held while the
|
||||
* lv is not active, but this helps.) The most common case where this
|
||||
* is helpful is when the lv lock operation is slow/delayed and the
|
||||
* command is canceled by the user.
|
||||
*
|
||||
* LV_UNLOCK means the lv unlock action was generated by lvmlockd when
|
||||
* it tried to send the reply for an lv lock action (with LV_LOCK set),
|
||||
* and failed to send the reply to the client/command. The
|
||||
* last_client_id saved on the resource is compared to this LV_UNLOCK
|
||||
* action before the auto unlock is done in case another action locked
|
||||
* the lv between the failed client lock action and the auto unlock.
|
||||
*/
|
||||
if (r->type == LD_RT_LV)
|
||||
act->flags |= LD_AF_LV_LOCK;
|
||||
|
||||
list_add_tail(&lk->list, &r->locks);
|
||||
|
||||
return rv;
|
||||
@@ -1309,7 +1331,9 @@ static int res_convert(struct lockspace *ls, struct resource *r,
|
||||
uint32_t r_version;
|
||||
int rv;
|
||||
|
||||
log_debug("S %s R %s res_convert mode %d", ls->name, r->name, act->mode);
|
||||
r->last_client_id = act->client_id;
|
||||
|
||||
log_debug("S %s R %s res_convert cl %u mode %d", ls->name, r->name, act->client_id, act->mode);
|
||||
|
||||
if (act->mode == LD_LK_EX && lk->mode == LD_LK_SH && r->sh_count > 1)
|
||||
return -EAGAIN;
|
||||
@@ -1387,7 +1411,7 @@ static int res_cancel(struct lockspace *ls, struct resource *r,
|
||||
return -ENOENT;
|
||||
|
||||
do_cancel:
|
||||
log_debug("S %s R %s res_cancel client %d", ls->name, r->name, cact->client_id);
|
||||
log_debug("S %s R %s res_cancel cl %u", ls->name, r->name, cact->client_id);
|
||||
cact->result = -ECANCELED;
|
||||
list_del(&cact->list);
|
||||
add_client_result(cact);
|
||||
@@ -1435,22 +1459,32 @@ static int res_unlock(struct lockspace *ls, struct resource *r,
|
||||
}
|
||||
|
||||
if (act->op != LD_OP_CLOSE)
|
||||
log_debug("S %s R %s res_unlock no locks", ls->name, r->name);
|
||||
log_debug("S %s R %s res_unlock cl %u no locks", ls->name, r->name, act->client_id);
|
||||
return -ENOENT;
|
||||
|
||||
do_unlock:
|
||||
if ((act->flags & LD_AF_LV_UNLOCK) && (r->last_client_id != act->client_id)) {
|
||||
log_debug("S %s R %s res_unlock cl %u for failed client ignored, last client %u",
|
||||
ls->name, r->name, act->client_id, r->last_client_id);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
r->last_client_id = act->client_id;
|
||||
|
||||
if (act->op == LD_OP_CLOSE)
|
||||
log_debug("S %s R %s res_unlock from close", ls->name, r->name);
|
||||
log_debug("S %s R %s res_unlock cl %u from close", ls->name, r->name, act->client_id);
|
||||
else if (r->type == LD_RT_LV)
|
||||
log_debug("S %s R %s res_unlock (%s)", ls->name, r->name, act->lv_name);
|
||||
log_debug("S %s R %s res_unlock cl %u (%s)", ls->name, r->name, act->client_id, act->lv_name);
|
||||
else
|
||||
log_debug("S %s R %s res_unlock", ls->name, r->name);
|
||||
log_debug("S %s R %s res_unlock cl %u", ls->name, r->name, act->client_id);
|
||||
|
||||
/* send unlock to lm when last sh lock is unlocked */
|
||||
if (lk->mode == LD_LK_SH) {
|
||||
r->sh_count--;
|
||||
if (r->sh_count > 0)
|
||||
if (r->sh_count > 0) {
|
||||
log_debug("S %s R %s res_unlock sh_count %u", ls->name, r->name, r->sh_count);
|
||||
goto rem_lk;
|
||||
}
|
||||
}
|
||||
|
||||
if ((r->type == LD_RT_GL) && (r->mode == LD_LK_EX)) {
|
||||
@@ -1498,14 +1532,14 @@ static int res_update(struct lockspace *ls, struct resource *r,
|
||||
|
||||
lk = find_lock_client(r, act->client_id);
|
||||
if (!lk) {
|
||||
log_error("S %s R %s res_update client %u lock not found",
|
||||
log_error("S %s R %s res_update cl %u lock not found",
|
||||
ls->name, r->name, act->client_id);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (r->mode != LD_LK_EX) {
|
||||
log_error("S %s R %s res_update version on non-ex lock",
|
||||
ls->name, r->name);
|
||||
log_error("S %s R %s res_update cl %u version on non-ex lock",
|
||||
ls->name, r->name, act->client_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1516,7 +1550,7 @@ static int res_update(struct lockspace *ls, struct resource *r,
|
||||
else
|
||||
lk->version = act->version;
|
||||
|
||||
log_debug("S %s R %s res_update lk version to %u", ls->name, r->name, lk->version);
|
||||
log_debug("S %s R %s res_update cl %u lk version to %u", ls->name, r->name, act->client_id, lk->version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1716,6 +1750,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
continue;
|
||||
} else {
|
||||
/* success */
|
||||
r->last_client_id = act->client_id;
|
||||
act->result = -EALREADY;
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
@@ -1750,6 +1785,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
continue;
|
||||
} else {
|
||||
/* success */
|
||||
r->last_client_id = act->client_id;
|
||||
act->result = -EALREADY;
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
@@ -1787,6 +1823,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
|
||||
if ((lk->mode == LD_LK_EX) ||
|
||||
(lk->mode == LD_LK_SH && act->mode == LD_LK_SH)) {
|
||||
r->last_client_id = act->client_id;
|
||||
act->result = 0;
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
@@ -1794,6 +1831,7 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
/* persistent lock is sh, transient request is ex */
|
||||
/* FIXME: can we remove this case? do a convert here? */
|
||||
log_debug("res_process %s existing persistent lock new transient", r->name);
|
||||
r->last_client_id = act->client_id;
|
||||
act->result = -EEXIST;
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
@@ -1828,10 +1866,12 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
if (lk->mode != act->mode) {
|
||||
/* FIXME: convert and change to persistent? */
|
||||
log_debug("res_process %s existing transient lock new persistent", r->name);
|
||||
r->last_client_id = act->client_id;
|
||||
act->result = -EEXIST;
|
||||
list_del(&act->list);
|
||||
add_client_result(act);
|
||||
} else {
|
||||
r->last_client_id = act->client_id;
|
||||
lk->flags |= LD_LF_PERSISTENT;
|
||||
lk->client_id = 0;
|
||||
act->result = 0;
|
||||
@@ -1880,7 +1920,6 @@ static void res_process(struct lockspace *ls, struct resource *r,
|
||||
* lv lock conflicts won't be transient so don't retry them.
|
||||
*/
|
||||
|
||||
|
||||
if (r->mode == LD_LK_EX)
|
||||
return;
|
||||
|
||||
@@ -3491,14 +3530,14 @@ static void client_resume(struct client *cl)
|
||||
|
||||
if (!cl->poll_ignore || cl->fd == -1 || cl->pi == -1) {
|
||||
/* shouldn't happen */
|
||||
log_error("client_resume %d bad state ig %d fd %d pi %d",
|
||||
log_error("client_resume %u bad state ig %d fd %d pi %d",
|
||||
cl->id, cl->poll_ignore, cl->fd, cl->pi);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&pollfd_mutex);
|
||||
if (pollfd[cl->pi].fd != POLL_FD_IGNORE) {
|
||||
log_error("client_resume %d pi %d fd %d not IGNORE",
|
||||
log_error("client_resume %u pi %d fd %d not IGNORE",
|
||||
cl->id, cl->pi, cl->fd);
|
||||
}
|
||||
pollfd[cl->pi].fd = cl->fd;
|
||||
@@ -3509,16 +3548,17 @@ static void client_resume(struct client *cl)
|
||||
}
|
||||
|
||||
/* called from client_thread, cl->mutex is held */
|
||||
static void client_send_result(struct client *cl, struct action *act)
|
||||
static int client_send_result(struct client *cl, struct action *act)
|
||||
{
|
||||
response res;
|
||||
char result_flags[128];
|
||||
int dump_len = 0;
|
||||
int dump_fd = -1;
|
||||
int rv = 0;
|
||||
|
||||
if (cl->dead) {
|
||||
log_debug("client send %d skip dead", cl->id);
|
||||
return;
|
||||
log_debug("send cl %u skip dead", cl->id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(result_flags, 0, sizeof(result_flags));
|
||||
@@ -3580,7 +3620,7 @@ static void client_send_result(struct client *cl, struct action *act)
|
||||
if (act->lv_args[0])
|
||||
lv_args = act->lv_args;
|
||||
|
||||
log_debug("send %s[%d.%u] %s %s rv %d vg_args %s lv_args %s",
|
||||
log_debug("send %s[%d] cl %u %s %s rv %d vg_args %s lv_args %s",
|
||||
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
|
||||
op_str(act->op), rt_str(act->rt),
|
||||
act->result, vg_args ? vg_args : "", lv_args ? lv_args : "");
|
||||
@@ -3612,7 +3652,7 @@ static void client_send_result(struct client *cl, struct action *act)
|
||||
else
|
||||
act->result = -EINVAL;
|
||||
|
||||
log_debug("send %s[%d.%u] dump result %d dump_len %d",
|
||||
log_debug("send %s[%d] cl %u dump result %d dump_len %d",
|
||||
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
|
||||
act->result, dump_len);
|
||||
|
||||
@@ -3625,7 +3665,7 @@ static void client_send_result(struct client *cl, struct action *act)
|
||||
* A normal reply.
|
||||
*/
|
||||
|
||||
log_debug("send %s[%d.%u] %s %s rv %d %s %s",
|
||||
log_debug("send %s[%d] cl %u %s %s rv %d %s %s",
|
||||
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
|
||||
op_str(act->op), rt_str(act->rt),
|
||||
act->result, (act->result == -ENOLS) ? "ENOLS" : "", result_flags);
|
||||
@@ -3639,7 +3679,13 @@ static void client_send_result(struct client *cl, struct action *act)
|
||||
NULL);
|
||||
}
|
||||
|
||||
buffer_write(cl->fd, &res.buffer);
|
||||
if (!buffer_write(cl->fd, &res.buffer)) {
|
||||
rv = -errno;
|
||||
if (rv >= 0)
|
||||
rv = -1;
|
||||
log_debug("send cl %u fd %d error %d", cl->id, cl->fd, rv);
|
||||
}
|
||||
|
||||
buffer_destroy(&res.buffer);
|
||||
|
||||
client_resume(cl);
|
||||
@@ -3649,6 +3695,8 @@ static void client_send_result(struct client *cl, struct action *act)
|
||||
send_dump_buf(dump_fd, dump_len);
|
||||
close(dump_fd);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* called from client_thread */
|
||||
@@ -4303,10 +4351,10 @@ static void client_recv_action(struct client *cl)
|
||||
rv = buffer_read(cl->fd, &req.buffer);
|
||||
if (!rv) {
|
||||
if (errno == ECONNRESET) {
|
||||
log_debug("client recv %d ECONNRESET", cl->id);
|
||||
log_debug("client recv %u ECONNRESET", cl->id);
|
||||
cl->dead = 1;
|
||||
} else {
|
||||
log_error("client recv %d buffer_read error %d", cl->id, errno);
|
||||
log_error("client recv %u buffer_read error %d", cl->id, errno);
|
||||
}
|
||||
buffer_destroy(&req.buffer);
|
||||
client_resume(cl);
|
||||
@@ -4315,7 +4363,7 @@ static void client_recv_action(struct client *cl)
|
||||
|
||||
req.cft = dm_config_from_string(req.buffer.mem);
|
||||
if (!req.cft) {
|
||||
log_error("client recv %d config_from_string error", cl->id);
|
||||
log_error("client recv %u config_from_string error", cl->id);
|
||||
buffer_destroy(&req.buffer);
|
||||
client_resume(cl);
|
||||
return;
|
||||
@@ -4324,7 +4372,7 @@ static void client_recv_action(struct client *cl)
|
||||
str = daemon_request_str(req, "request", NULL);
|
||||
rv = str_to_op_rt(str, &op, &rt);
|
||||
if (rv < 0) {
|
||||
log_error("client recv %d bad request name \"%s\"", cl->id, str ? str : "");
|
||||
log_error("client recv %u bad request name \"%s\"", cl->id, str ? str : "");
|
||||
dm_config_destroy(req.cft);
|
||||
buffer_destroy(&req.buffer);
|
||||
client_resume(cl);
|
||||
@@ -4447,7 +4495,7 @@ static void client_recv_action(struct client *cl)
|
||||
dm_config_destroy(req.cft);
|
||||
buffer_destroy(&req.buffer);
|
||||
|
||||
log_debug("recv %s[%d.%u] %s %s \"%s\" mode %s flags %x",
|
||||
log_debug("recv %s[%d] cl %u %s %s \"%s\" mode %s flags %x",
|
||||
cl->name[0] ? cl->name : "client", cl->pid, cl->id,
|
||||
op_str(act->op), rt_str(act->rt), act->vg_name, mode_str(act->mode), opts);
|
||||
|
||||
@@ -4514,6 +4562,8 @@ static void *client_thread_main(void *arg_in)
|
||||
{
|
||||
struct client *cl;
|
||||
struct action *act;
|
||||
struct action *act_un;
|
||||
int rv;
|
||||
|
||||
while (1) {
|
||||
pthread_mutex_lock(&client_mutex);
|
||||
@@ -4537,11 +4587,30 @@ static void *client_thread_main(void *arg_in)
|
||||
|
||||
if (cl) {
|
||||
pthread_mutex_lock(&cl->mutex);
|
||||
client_send_result(cl, act);
|
||||
rv = client_send_result(cl, act);
|
||||
pthread_mutex_unlock(&cl->mutex);
|
||||
} else {
|
||||
log_debug("no client for result");
|
||||
log_debug("no client %u for result", act->client_id);
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The client failed after we acquired an LV lock for
|
||||
* it, but before getting this reply saying it's done.
|
||||
* So the lv will not be active and we should release
|
||||
* the lv lock it requested.
|
||||
*/
|
||||
if ((rv < 0) && (act->flags & LD_AF_LV_LOCK)) {
|
||||
log_debug("auto unlock lv for failed client %u", act->client_id);
|
||||
if ((act_un = alloc_action())) {
|
||||
memcpy(act_un, act, sizeof(struct action));
|
||||
act_un->mode = LD_LK_UN;
|
||||
act_un->flags |= LD_AF_LV_UNLOCK;
|
||||
act_un->flags &= ~LD_AF_LV_LOCK;
|
||||
add_lock_action(act_un);
|
||||
}
|
||||
}
|
||||
|
||||
free_action(act);
|
||||
continue;
|
||||
}
|
||||
@@ -4571,6 +4640,7 @@ static void *client_thread_main(void *arg_in)
|
||||
log_debug("client rem %d pi %d fd %d ig %d",
|
||||
cl->id, cl->pi, cl->fd, cl->poll_ignore);
|
||||
*/
|
||||
|
||||
/*
|
||||
* If cl->dead was set in main_loop, then the
|
||||
* fd has already been closed and the pollfd
|
||||
@@ -5620,7 +5690,7 @@ static void process_listener(int poll_fd)
|
||||
list_add_tail(&cl->list, &client_list);
|
||||
pthread_mutex_unlock(&client_mutex);
|
||||
|
||||
log_debug("client add id %d pi %d fd %d", cl->id, cl->pi, cl->fd);
|
||||
log_debug("new cl %u pi %d fd %d", cl->id, cl->pi, cl->fd);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5763,14 +5833,14 @@ static int main_loop(daemon_state *ds_arg)
|
||||
|
||||
if (cl->recv) {
|
||||
/* should not happen */
|
||||
log_error("main client %d already recv", cl->id);
|
||||
log_error("main client %u already recv", cl->id);
|
||||
|
||||
} else if (cl->dead) {
|
||||
/* should not happen */
|
||||
log_error("main client %d already dead", cl->id);
|
||||
log_error("main client %u already dead", cl->id);
|
||||
|
||||
} else if (is_dead) {
|
||||
log_debug("close %s[%d.%u] fd %d",
|
||||
log_debug("close %s[%d] cl %u fd %d",
|
||||
cl->name[0] ? cl->name : "client",
|
||||
cl->pid, cl->id, cl->fd);
|
||||
cl->dead = 1;
|
||||
|
||||
@@ -103,6 +103,8 @@ struct client {
|
||||
#define LD_AF_DUP_GL_LS 0x00002000
|
||||
#define LD_AF_ADOPT 0x00010000
|
||||
#define LD_AF_WARN_GL_REMOVED 0x00020000
|
||||
#define LD_AF_LV_LOCK 0x00040000
|
||||
#define LD_AF_LV_UNLOCK 0x00080000
|
||||
|
||||
/*
|
||||
* Number of times to repeat a lock request after
|
||||
@@ -141,6 +143,7 @@ struct resource {
|
||||
int8_t mode;
|
||||
unsigned int sh_count; /* number of sh locks on locks list */
|
||||
uint32_t version;
|
||||
uint32_t last_client_id; /* last client_id to lock or unlock resource */
|
||||
unsigned int lm_init : 1; /* lm_data is initialized */
|
||||
unsigned int adopt : 1; /* temp flag in remove_inactive_lvs */
|
||||
unsigned int version_zero_valid : 1;
|
||||
|
||||
@@ -1392,6 +1392,15 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
if (adopt)
|
||||
flags |= SANLK_ACQUIRE_ORPHAN_ONLY;
|
||||
|
||||
#ifdef SANLOCK_HAS_ACQUIRE_OWNER_NOWAIT
|
||||
/*
|
||||
* Don't block waiting for a failed lease to expire since it causes
|
||||
* sanlock_acquire to block for a long time, which would prevent this
|
||||
* thread from processing other lock requests.
|
||||
*/
|
||||
flags |= SANLK_ACQUIRE_OWNER_NOWAIT;
|
||||
#endif
|
||||
|
||||
rv = sanlock_acquire(lms->sock, -1, flags, 1, &rs, NULL);
|
||||
|
||||
if (rv == -EAGAIN) {
|
||||
@@ -1462,6 +1471,26 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
#ifdef SANLOCK_HAS_ACQUIRE_OWNER_NOWAIT
|
||||
if (rv == SANLK_ACQUIRE_OWNED_RETRY) {
|
||||
/*
|
||||
* The lock is held by a failed host, and will eventually
|
||||
* expire. If we retry we'll eventually acquire the lock
|
||||
* (or find someone else has acquired it). The EAGAIN retry
|
||||
* attempts for SH locks above would not be sufficient for
|
||||
* the length of expiration time. We could add a longer
|
||||
* retry time here to cover the full expiration time and block
|
||||
* the activation command for that long. For now just return
|
||||
* the standard error indicating that another host still owns
|
||||
* the lease. FIXME: return a different error number so the
|
||||
* command can print an different error indicating that the
|
||||
* owner of the lease is in the process of expiring?
|
||||
*/
|
||||
log_debug("S %s R %s lock_san acquire mode %d rv %d", ls->name, r->name, ld_mode, rv);
|
||||
*retry = 0;
|
||||
return -EAGAIN;
|
||||
}
|
||||
#endif
|
||||
if (rv < 0) {
|
||||
log_error("S %s R %s lock_san acquire error %d",
|
||||
ls->name, r->name, rv);
|
||||
|
||||
@@ -62,6 +62,7 @@ SOURCES =\
|
||||
device/dev-swap.c \
|
||||
device/dev-type.c \
|
||||
device/dev-luks.c \
|
||||
device/dev-dasd.c \
|
||||
display/display.c \
|
||||
error/errseg.c \
|
||||
unknown/unknown.c \
|
||||
|
||||
@@ -143,23 +143,23 @@ static int _get_segment_status_from_target_params(const char *target_name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(segtype->name, "cache")) {
|
||||
if (segtype_is_cache(segtype)) {
|
||||
if (!dm_get_status_cache(seg_status->mem, params, &(seg_status->cache)))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_CACHE;
|
||||
} else if (!strcmp(segtype->name, "raid")) {
|
||||
} else if (segtype_is_raid(segtype)) {
|
||||
if (!dm_get_status_raid(seg_status->mem, params, &seg_status->raid))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_RAID;
|
||||
} else if (!strcmp(segtype->name, "thin")) {
|
||||
} else if (segtype_is_thin_volume(segtype)) {
|
||||
if (!dm_get_status_thin(seg_status->mem, params, &seg_status->thin))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_THIN;
|
||||
} else if (!strcmp(segtype->name, "thin-pool")) {
|
||||
} else if (segtype_is_thin_pool(segtype)) {
|
||||
if (!dm_get_status_thin_pool(seg_status->mem, params, &seg_status->thin_pool))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_THIN_POOL;
|
||||
} else if (!strcmp(segtype->name, "snapshot")) {
|
||||
} else if (segtype_is_snapshot(segtype)) {
|
||||
if (!dm_get_status_snapshot(seg_status->mem, params, &seg_status->snapshot))
|
||||
return_0;
|
||||
seg_status->type = SEG_STATUS_SNAPSHOT;
|
||||
@@ -3277,7 +3277,7 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
break;
|
||||
case SUSPEND:
|
||||
dm_tree_skip_lockfs(root);
|
||||
if (!dm->flush_required && lv_is_mirror(lv) && !lv_is_pvmove(lv))
|
||||
if (!dm->flush_required && !lv_is_pvmove(lv))
|
||||
dm_tree_use_no_flush_suspend(root);
|
||||
/* Fall through */
|
||||
case SUSPEND_WITH_LOCKFS:
|
||||
@@ -3296,7 +3296,14 @@ static int _tree_action(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
if (!dm_tree_preload_children(root, dlid, DLID_SIZE))
|
||||
goto_out;
|
||||
|
||||
if (dm_tree_node_size_changed(root))
|
||||
if ((dm_tree_node_size_changed(root) < 0))
|
||||
dm->flush_required = 1;
|
||||
|
||||
/* Currently keep the code require flush for any
|
||||
* non 'thin pool/volume, mirror' or with any size change */
|
||||
if (!lv_is_thin_volume(lv) &&
|
||||
!lv_is_thin_pool(lv) &&
|
||||
(!lv_is_mirror(lv) || dm_tree_node_size_changed(root)))
|
||||
dm->flush_required = 1;
|
||||
|
||||
if (action == ACTIVATE) {
|
||||
|
||||
32
lib/cache/lvmcache.c
vendored
32
lib/cache/lvmcache.c
vendored
@@ -1542,10 +1542,6 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg
|
||||
vgid = vgname;
|
||||
}
|
||||
|
||||
/* When using lvmetad, the PV could not have become orphaned. */
|
||||
if (lvmetad_active() && is_orphan_vg(vgname) && info->vginfo)
|
||||
return 1;
|
||||
|
||||
/* If PV without mdas is already in a real VG, don't make it orphan */
|
||||
if (is_orphan_vg(vgname) && info->vginfo &&
|
||||
mdas_empty_or_ignored(&info->mdas) &&
|
||||
@@ -1871,8 +1867,8 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
* device already exists? Things don't seem to work
|
||||
* if we do that for some reason.
|
||||
*/
|
||||
log_verbose("Found same device %s with same pvid %s",
|
||||
dev_name(existing->dev), pvid_s);
|
||||
log_debug_cache("Found same device %s with same pvid %s",
|
||||
dev_name(existing->dev), pvid_s);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2358,3 +2354,27 @@ int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lvmcache_get_max_name_lengths(struct cmd_context *cmd,
|
||||
unsigned *pv_max_name_len,
|
||||
unsigned *vg_max_name_len)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_info *info;
|
||||
unsigned len;
|
||||
|
||||
*vg_max_name_len = 0;
|
||||
*pv_max_name_len = 0;
|
||||
|
||||
dm_list_iterate_items(vginfo, &_vginfos) {
|
||||
len = strlen(vginfo->vgname);
|
||||
if (*vg_max_name_len < len)
|
||||
*vg_max_name_len = len;
|
||||
|
||||
dm_list_iterate_items(info, &vginfo->infos) {
|
||||
len = strlen(dev_name(info->dev));
|
||||
if (*pv_max_name_len < len)
|
||||
*pv_max_name_len = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4
lib/cache/lvmcache.h
vendored
4
lib/cache/lvmcache.h
vendored
@@ -190,4 +190,8 @@ void lvmcache_set_preferred_duplicates(const char *vgid);
|
||||
|
||||
int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd);
|
||||
|
||||
void lvmcache_get_max_name_lengths(struct cmd_context *cmd,
|
||||
unsigned *pv_max_name_len, unsigned *vg_max_name_len);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
94
lib/cache/lvmetad.c
vendored
94
lib/cache/lvmetad.c
vendored
@@ -37,6 +37,70 @@ static struct cmd_context *_lvmetad_cmd = NULL;
|
||||
|
||||
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
static int _log_debug_inequality(const char *name, struct dm_config_node *a, struct dm_config_node *b)
|
||||
{
|
||||
int result = 0;
|
||||
int final_result = 0;
|
||||
|
||||
if (a->v && b->v) {
|
||||
result = compare_value(a->v, b->v);
|
||||
if (result) {
|
||||
struct dm_config_value *av = a->v;
|
||||
struct dm_config_value *bv = b->v;
|
||||
|
||||
if (!strcmp(a->key, b->key)) {
|
||||
if (a->v->type == DM_CFG_STRING && b->v->type == DM_CFG_STRING)
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s: %s / %s",
|
||||
name, a->key, b->key, av->v.str, bv->v.str);
|
||||
else if (a->v->type == DM_CFG_INT && b->v->type == DM_CFG_INT)
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s: " FMTi64 " / " FMTi64,
|
||||
name, a->key, b->key, av->v.i, bv->v.i);
|
||||
else
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s: type %d / type %d",
|
||||
name, a->key, b->key, av->type, bv->type);
|
||||
} else {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
}
|
||||
final_result = result;
|
||||
}
|
||||
}
|
||||
|
||||
if (a->v && !b->v) {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
final_result = 1;
|
||||
}
|
||||
|
||||
if (!a->v && b->v) {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
final_result = -1;
|
||||
}
|
||||
|
||||
if (a->child && b->child) {
|
||||
result = _log_debug_inequality(name, a->child, b->child);
|
||||
if (result)
|
||||
final_result = result;
|
||||
}
|
||||
|
||||
if (a->sib && b->sib) {
|
||||
result = _log_debug_inequality(name, a->sib, b->sib);
|
||||
if (result)
|
||||
final_result = result;
|
||||
}
|
||||
|
||||
|
||||
if (a->sib && !b->sib) {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
final_result = 1;
|
||||
}
|
||||
|
||||
if (!a->sib && b->sib) {
|
||||
log_debug_lvmetad("VG %s metadata inequality at %s / %s", name, a->key, b->key);
|
||||
final_result = -1;
|
||||
}
|
||||
|
||||
return final_result;
|
||||
}
|
||||
|
||||
void lvmetad_disconnect(void)
|
||||
{
|
||||
if (_lvmetad_connected)
|
||||
@@ -1122,6 +1186,8 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
|
||||
* due to something like an lvcreate from another host.
|
||||
* This is limited to changes that only affect the vg (not global state like
|
||||
* orphan PVs), so we only need to reread mdas on the vg's existing pvs.
|
||||
* But, a previous PV in the VG may have been removed since we last read
|
||||
* the VG, and that PV may have been reused for another VG.
|
||||
*/
|
||||
|
||||
static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
@@ -1134,6 +1200,7 @@ static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct vo
|
||||
struct format_instance *fid;
|
||||
struct format_instance_ctx fic = { .type = 0 };
|
||||
struct _lvmetad_pvscan_baton baton;
|
||||
struct device *save_dev = NULL;
|
||||
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
/* missing pv */
|
||||
@@ -1160,9 +1227,25 @@ static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct vo
|
||||
|
||||
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
|
||||
|
||||
/*
|
||||
* The PV may have been removed from the VG by another host
|
||||
* since we last read the VG.
|
||||
*/
|
||||
if (!baton.vg) {
|
||||
log_debug_lvmetad("Did not find VG %s in scan of PV %s", vg->name, dev_name(pvl->pv->dev));
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
return NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* The PV may have been removed from the VG and used for a
|
||||
* different VG since we last read the VG.
|
||||
*/
|
||||
if (strcmp(baton.vg->name, vg->name)) {
|
||||
log_debug_lvmetad("Did not find VG %s in scan of PV %s which is now VG %s",
|
||||
vg->name, dev_name(pvl->pv->dev), baton.vg->name);
|
||||
release_vg(baton.vg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
|
||||
@@ -1173,9 +1256,12 @@ static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct vo
|
||||
|
||||
if (!vgmeta_ret) {
|
||||
vgmeta_ret = vgmeta;
|
||||
save_dev = pvl->pv->dev;
|
||||
} else {
|
||||
if (compare_config(vgmeta_ret->root, vgmeta->root)) {
|
||||
log_error("VG metadata comparison failed");
|
||||
log_error("VG %s metadata comparison failed for device %s vs %s",
|
||||
vg->name, dev_name(pvl->pv->dev), save_dev ? dev_name(save_dev) : "none");
|
||||
_log_debug_inequality(vg->name, vgmeta_ret->root, vgmeta->root);
|
||||
dm_config_destroy(vgmeta);
|
||||
dm_config_destroy(vgmeta_ret);
|
||||
release_vg(baton.vg);
|
||||
@@ -1245,7 +1331,7 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
|
||||
log_warn("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
||||
baton.fid->fmt->name, dev_name(dev));
|
||||
else
|
||||
log_error("WARNING: Ignoring obsolete format of metadata (%s) on device %s when using lvmetad",
|
||||
log_error("Ignoring obsolete format of metadata (%s) on device %s when using lvmetad.",
|
||||
baton.fid->fmt->name, dev_name(dev));
|
||||
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
|
||||
|
||||
@@ -1597,7 +1683,7 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lvmetad_used())
|
||||
if (!lvmetad_active())
|
||||
return;
|
||||
|
||||
log_debug_lvmetad("Validating global lvmetad cache");
|
||||
|
||||
@@ -420,7 +420,7 @@ int init_cache_segtypes(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
segtype->name = "cache-pool";
|
||||
segtype->name = SEG_TYPE_NAME_CACHE_POOL;
|
||||
segtype->flags = SEG_CACHE_POOL | SEG_CANNOT_BE_ZEROED | SEG_ONLY_EXCLUSIVE;
|
||||
segtype->ops = &_cache_pool_ops;
|
||||
|
||||
@@ -434,7 +434,7 @@ int init_cache_segtypes(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
segtype->name = "cache";
|
||||
segtype->name = SEG_TYPE_NAME_CACHE;
|
||||
segtype->flags = SEG_CACHE | SEG_ONLY_EXCLUSIVE;
|
||||
segtype->ops = &_cache_ops;
|
||||
|
||||
|
||||
@@ -362,7 +362,8 @@ static void _init_logging(struct cmd_context *cmd)
|
||||
|
||||
/* Tell device-mapper about our logging */
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
dm_log_with_errno_init(print_log);
|
||||
if (!dm_log_is_non_default())
|
||||
dm_log_with_errno_init(print_log);
|
||||
#endif
|
||||
reset_log_duplicated();
|
||||
reset_lvm_errno(1);
|
||||
|
||||
@@ -474,8 +474,8 @@ cfg(allocation_cache_policy_CFG, "cache_policy", allocation_CFG_SECTION, CFG_PRO
|
||||
"otherwise the older mq (Multiqueue) policy is selected.\n")
|
||||
|
||||
cfg_section(allocation_cache_settings_CFG_SECTION, "cache_settings", allocation_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, vsn(2, 2, 128), 0, NULL,
|
||||
"Individual settings for policies.\n"
|
||||
"See the help for individual policies for more info.\n")
|
||||
"Settings for the cache policy.\n"
|
||||
"See documentation for individual cache policies for more info.\n")
|
||||
|
||||
cfg_section(policy_settings_CFG_SUBSECTION, "policy_settings", allocation_cache_settings_CFG_SECTION, CFG_NAME_VARIABLE | CFG_SECTION_NO_CHECK | CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, vsn(2, 2, 128), 0, NULL,
|
||||
"Replace this subsection name with a policy name.\n"
|
||||
@@ -1416,10 +1416,20 @@ cfg(disk_area_size_CFG, "size", disk_area_CFG_SUBSECTION, CFG_UNSUPPORTED | CFG_
|
||||
cfg(disk_area_id_CFG, "id", disk_area_CFG_SUBSECTION, CFG_UNSUPPORTED | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, NULL)
|
||||
|
||||
cfg(report_compact_output_CFG, "compact_output", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_COMPACT_OUTPUT, vsn(2, 2, 115), NULL, 0, NULL,
|
||||
"Do not print empty report fields.\n"
|
||||
"Fields that don't have a value set for any of the rows reported are\n"
|
||||
"skipped and not printed. Compact output is applicable only if\n"
|
||||
"report/buffered is enabled.\n")
|
||||
"Do not print empty values for all report fields.\n"
|
||||
"If enabled, all fields that don't have a value set for any of the\n"
|
||||
"rows reported are skipped and not printed. Compact output is\n"
|
||||
"applicable only if report/buffered is enabled. If you need to\n"
|
||||
"compact only specified fields, use compact_output=0 and define\n"
|
||||
"report/compact_output_cols configuration setting instead.\n")
|
||||
|
||||
cfg(report_compact_output_cols_CFG, "compact_output_cols", report_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_COMPACT_OUTPUT_COLS, vsn(2, 2, 133), NULL, 0, NULL,
|
||||
"Do not print empty values for specified report fields.\n"
|
||||
"If defined, specified fields that don't have a value set for any\n"
|
||||
"of the rows reported are skipped and not printed. Compact output\n"
|
||||
"is applicable only if report/buffered is enabled. If you need to\n"
|
||||
"compact all fields, use compact_output=1 instead in which case\n"
|
||||
"the compact_output_cols setting is then ignored.\n")
|
||||
|
||||
cfg(report_aligned_CFG, "aligned", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_ALIGNED, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
"Align columns in report output.\n")
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
|
||||
#define DEFAULT_MIRROR_IMAGE_FAULT_POLICY "remove"
|
||||
#define DEFAULT_MIRROR_MAX_IMAGES 8 /* limited by kernel DM_KCOPYD_MAX_REGIONS */
|
||||
#define DEFAULT_RAID_MAX_IMAGES 8
|
||||
|
||||
#define DEFAULT_RAID_FAULT_POLICY "warn"
|
||||
|
||||
#define DEFAULT_DMEVENTD_RAID_LIB "libdevmapper-event-lvm2raid.so"
|
||||
@@ -199,6 +201,8 @@
|
||||
#define DEFAULT_REP_LIST_ITEM_SEPARATOR ","
|
||||
#define DEFAULT_TIME_FORMAT "%Y-%m-%d %T %z"
|
||||
|
||||
#define DEFAULT_COMPACT_OUTPUT_COLS ""
|
||||
|
||||
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,pool_lv,origin,data_percent,metadata_percent,move_pv,mirror_log,copy_percent,convert_lv"
|
||||
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
|
||||
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
#include "lib.h"
|
||||
#include "str_list.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
struct dm_list *str_list_create(struct dm_pool *mem)
|
||||
{
|
||||
struct dm_list *sl;
|
||||
|
||||
if (!(sl = dm_pool_alloc(mem, sizeof(struct dm_list)))) {
|
||||
if (!(sl = mem ? dm_pool_alloc(mem, sizeof(struct dm_list))
|
||||
: dm_malloc(sizeof(struct dm_list)))) {
|
||||
log_errno(ENOMEM, "str_list allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
@@ -37,7 +40,8 @@ static int _str_list_add_no_dup_check(struct dm_pool *mem, struct dm_list *sll,
|
||||
if (!str)
|
||||
return_0;
|
||||
|
||||
if (!(sln = dm_pool_alloc(mem, sizeof(*sln))))
|
||||
if (!(sln = mem ? dm_pool_alloc(mem, sizeof(*sln))
|
||||
: dm_malloc(sizeof(*sln))))
|
||||
return_0;
|
||||
|
||||
sln->str = str;
|
||||
@@ -158,3 +162,101 @@ int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *str_list_to_str(struct dm_pool *mem, const struct dm_list *list,
|
||||
const char *delim)
|
||||
{
|
||||
size_t delim_len = strlen(delim);
|
||||
unsigned list_size = dm_list_size(list);
|
||||
struct dm_str_list *sl;
|
||||
char *str, *p;
|
||||
size_t len = 0;
|
||||
unsigned i = 0;
|
||||
|
||||
dm_list_iterate_items(sl, list)
|
||||
len += strlen(sl->str);
|
||||
if (list_size > 1)
|
||||
len += ((list_size - 1) * delim_len);
|
||||
|
||||
str = mem ? dm_pool_alloc(mem, len+1) : dm_malloc(len+1);
|
||||
if (!str) {
|
||||
log_error("str_list_to_str: string allocation failed.");
|
||||
return NULL;
|
||||
}
|
||||
str[len] = '\0';
|
||||
p = str;
|
||||
|
||||
dm_list_iterate_items(sl, list) {
|
||||
len = strlen(sl->str);
|
||||
memcpy(p, sl->str, len);
|
||||
p += len;
|
||||
|
||||
if (++i != list_size) {
|
||||
memcpy(p, delim, delim_len);
|
||||
p += delim_len;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
struct dm_list *str_to_str_list(struct dm_pool *mem, const char *str,
|
||||
const char *delim, int ignore_multiple_delim)
|
||||
{
|
||||
size_t delim_len = strlen(delim);
|
||||
struct dm_list *list;
|
||||
const char *p1, *p2, *next;
|
||||
char *str_item;
|
||||
size_t len;
|
||||
|
||||
if (!(list = str_list_create(mem))) {
|
||||
log_error("str_to_str_list: string list allocation failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p1 = p2 = str;
|
||||
while (*p1) {
|
||||
if (!(p2 = strstr(p1, delim)))
|
||||
next = p2 = str + strlen(str);
|
||||
else
|
||||
next = p2 + delim_len;
|
||||
|
||||
len = p2 - p1;
|
||||
str_item = mem ? dm_pool_alloc(mem, len+1) : dm_malloc(len+1);
|
||||
if (!str_item) {
|
||||
log_error("str_to_str_list: string list item allocation failed.");
|
||||
goto bad;
|
||||
}
|
||||
memcpy(str_item, p1, len);
|
||||
str_item[len] = '\0';
|
||||
|
||||
if (!str_list_add_no_dup_check(mem, list, str_item))
|
||||
goto_bad;
|
||||
|
||||
if (ignore_multiple_delim) {
|
||||
while (!strncmp(next, delim, delim_len))
|
||||
next += delim_len;
|
||||
}
|
||||
|
||||
p1 = next;
|
||||
}
|
||||
|
||||
return list;
|
||||
bad:
|
||||
if (mem)
|
||||
dm_pool_free(mem, list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void str_list_destroy(struct dm_list *list, int deallocate_strings)
|
||||
{
|
||||
struct dm_str_list *sl, *tmp_sl;
|
||||
|
||||
dm_list_iterate_items_safe(sl, tmp_sl, list) {
|
||||
dm_list_del(&sl->list);
|
||||
if (deallocate_strings)
|
||||
dm_free((char *)sl->str);
|
||||
dm_free(sl);
|
||||
}
|
||||
dm_free(list);
|
||||
}
|
||||
|
||||
@@ -30,5 +30,9 @@ int str_list_match_list(const struct dm_list *sll, const struct dm_list *sll2, c
|
||||
int str_list_lists_equal(const struct dm_list *sll, const struct dm_list *sll2);
|
||||
int str_list_dup(struct dm_pool *mem, struct dm_list *sllnew,
|
||||
const struct dm_list *sllold);
|
||||
char *str_list_to_str(struct dm_pool *mem, const struct dm_list *list, const char *delim);
|
||||
struct dm_list *str_to_str_list(struct dm_pool *mem, const char *str, const char *delim, int ignore_multiple_delim);
|
||||
/* Only for lists which were *not* allocated from the mem pool! */
|
||||
void str_list_destroy(struct dm_list *list, int deallocate_strings);
|
||||
|
||||
#endif
|
||||
|
||||
111
lib/device/dev-dasd.c
Normal file
111
lib/device/dev-dasd.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* 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
|
||||
* 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 "dev-type.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
/*
|
||||
* Interface taken from kernel header arch/s390/include/uapi/asm/dasd.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
|
||||
* Copyright IBM Corp. 1999, 2000
|
||||
* EMC Symmetrix ioctl Copyright EMC Corporation, 2008
|
||||
* Author.........: Nigel Hislop <hislop_nigel@emc.com>
|
||||
*/
|
||||
|
||||
#define DASD_IOCTL_LETTER 'D'
|
||||
#define DASD_API_VERSION 6
|
||||
|
||||
/*
|
||||
* struct dasd_information2_t
|
||||
* represents any data about the device, which is visible to userspace.
|
||||
* including foramt and featueres.
|
||||
*/
|
||||
typedef struct dasd_information2_t {
|
||||
unsigned int devno; /* S/390 devno */
|
||||
unsigned int real_devno; /* for aliases */
|
||||
unsigned int schid; /* S/390 subchannel identifier */
|
||||
unsigned int cu_type : 16; /* from SenseID */
|
||||
unsigned int cu_model : 8; /* from SenseID */
|
||||
unsigned int dev_type : 16; /* from SenseID */
|
||||
unsigned int dev_model : 8; /* from SenseID */
|
||||
unsigned int open_count;
|
||||
unsigned int req_queue_len;
|
||||
unsigned int chanq_len; /* length of chanq */
|
||||
char type[4]; /* from discipline.name, 'none' for unknown */
|
||||
unsigned int status; /* current device level */
|
||||
unsigned int label_block; /* where to find the VOLSER */
|
||||
unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
|
||||
unsigned int characteristics_size;
|
||||
unsigned int confdata_size;
|
||||
char characteristics[64]; /* from read_device_characteristics */
|
||||
char configuration_data[256]; /* from read_configuration_data */
|
||||
unsigned int format; /* format info like formatted/cdl/ldl/... */
|
||||
unsigned int features; /* dasd features like 'ro',... */
|
||||
unsigned int reserved0; /* reserved for further use ,... */
|
||||
unsigned int reserved1; /* reserved for further use ,... */
|
||||
unsigned int reserved2; /* reserved for further use ,... */
|
||||
unsigned int reserved3; /* reserved for further use ,... */
|
||||
unsigned int reserved4; /* reserved for further use ,... */
|
||||
unsigned int reserved5; /* reserved for further use ,... */
|
||||
unsigned int reserved6; /* reserved for further use ,... */
|
||||
unsigned int reserved7; /* reserved for further use ,... */
|
||||
} dasd_information2_t;
|
||||
|
||||
#define DASD_FORMAT_CDL 2
|
||||
|
||||
/* Get information on a dasd device (enhanced) */
|
||||
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER,3,dasd_information2_t)
|
||||
|
||||
/*
|
||||
* End of included interface.
|
||||
*/
|
||||
|
||||
int dasd_is_cdl_formatted(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
dasd_information2_t dasd_info2;
|
||||
|
||||
if (!dev_open_readonly(dev))
|
||||
return_0;
|
||||
|
||||
if (ioctl(dev->fd, BIODASDINFO2, &dasd_info2)) {
|
||||
log_sys_error("ioctl BIODASDINFO2", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dasd_info2.format == DASD_FORMAT_CDL)
|
||||
ret = 1;
|
||||
|
||||
out:
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int dasd_is_cdl_formatted(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -363,7 +363,7 @@ static int _native_dev_is_partitioned(struct dev_types *dt, struct device *dev)
|
||||
return 0;
|
||||
|
||||
/* Unpartitioned DASD devices are not supported. */
|
||||
if (MAJOR(dev->dev) == dt->dasd_major)
|
||||
if ((MAJOR(dev->dev) == dt->dasd_major) && dasd_is_cdl_formatted(dev))
|
||||
return 1;
|
||||
|
||||
if (!dev_open_readonly_quiet(dev)) {
|
||||
@@ -651,8 +651,13 @@ static int _wipe_known_signatures_with_blkid(struct device *dev, const char *nam
|
||||
BLKID_SUBLKS_BADCSUM);
|
||||
|
||||
while (!blkid_do_probe(probe)) {
|
||||
if ((r_wipe = _blkid_wipe(probe, dev, name, types_to_exclude, types_no_prompt, yes, force)) == 1)
|
||||
if ((r_wipe = _blkid_wipe(probe, dev, name, types_to_exclude, types_no_prompt, yes, force)) == 1) {
|
||||
(*wiped)++;
|
||||
if (blkid_probe_step_back(probe)) {
|
||||
log_error("Failed to step back blkid probe to check just wiped signature.");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* do not count excluded types */
|
||||
if (r_wipe != 2)
|
||||
found++;
|
||||
@@ -734,13 +739,20 @@ int wipe_known_signatures(struct cmd_context *cmd, struct device *dev,
|
||||
uint32_t types_no_prompt, int yes, force_t force,
|
||||
int *wiped)
|
||||
{
|
||||
int blkid_wiping_enabled = find_config_tree_bool(cmd, allocation_use_blkid_wiping_CFG, NULL);
|
||||
|
||||
#ifdef BLKID_WIPING_SUPPORT
|
||||
if (find_config_tree_bool(cmd, allocation_use_blkid_wiping_CFG, NULL))
|
||||
if (blkid_wiping_enabled)
|
||||
return _wipe_known_signatures_with_blkid(dev, name,
|
||||
types_to_exclude,
|
||||
types_no_prompt,
|
||||
yes, force, wiped);
|
||||
#endif
|
||||
if (blkid_wiping_enabled) {
|
||||
log_warn("allocation/use_blkid_wiping=1 configuration setting is set "
|
||||
"while LVM is not compiled with blkid wiping support.");
|
||||
log_warn("Falling back to native LVM signature detection.");
|
||||
}
|
||||
return _wipe_known_signatures_with_lvm(dev, name,
|
||||
types_to_exclude,
|
||||
types_no_prompt,
|
||||
|
||||
@@ -59,6 +59,7 @@ int major_is_scsi_device(struct dev_types *dt, int major);
|
||||
int dev_is_md(struct device *dev, uint64_t *sb);
|
||||
int dev_is_swap(struct device *dev, uint64_t *signature);
|
||||
int dev_is_luks(struct device *dev, uint64_t *signature);
|
||||
int dasd_is_cdl_formatted(struct device *dev);
|
||||
|
||||
/* Signature wiping. */
|
||||
#define TYPE_LVM1_MEMBER 0x001
|
||||
|
||||
@@ -95,7 +95,7 @@ struct segment_type *init_error_segtype(struct cmd_context *cmd)
|
||||
return_NULL;
|
||||
|
||||
segtype->ops = &_error_ops;
|
||||
segtype->name = "error";
|
||||
segtype->name = SEG_TYPE_NAME_ERROR;
|
||||
segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
@@ -219,7 +219,7 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
while (le < lvm->lv->le_count) {
|
||||
@@ -281,7 +281,7 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
|
||||
total_area_len = lvm->lv->le_count / lvm->stripes;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
while (first_area_le < total_area_len) {
|
||||
|
||||
@@ -188,8 +188,7 @@ static int _add_stripe_seg(struct dm_pool *mem,
|
||||
|
||||
area_len = (usp->devs[0].blocks) / POOL_PE_SIZE;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd,
|
||||
"striped")))
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
if (!(seg = alloc_lv_segment(segtype, lv, *le_cur,
|
||||
@@ -226,7 +225,7 @@ static int _add_linear_seg(struct dm_pool *mem,
|
||||
unsigned j;
|
||||
uint32_t area_len;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
for (j = 0; j < usp->num_devs; j++) {
|
||||
|
||||
@@ -654,7 +654,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
|
||||
if ((new_wrap && old_wrap) ||
|
||||
(rlocn && (new_wrap || old_wrap) && (new_end > rlocn->offset)) ||
|
||||
(mdac->rlocn.size >= mdah->size)) {
|
||||
(MDA_HEADER_SIZE + (rlocn ? rlocn->size : 0) + mdac->rlocn.size >= mdah->size)) {
|
||||
log_error("VG %s metadata too large for circular buffer",
|
||||
vg->name);
|
||||
goto out;
|
||||
@@ -1339,6 +1339,7 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
|
||||
|
||||
label = lvmcache_get_label(info);
|
||||
label->sector = pv->label_sector;
|
||||
label->dev = pv->dev;
|
||||
|
||||
lvmcache_update_pv(info, pv, fmt);
|
||||
|
||||
@@ -2145,7 +2146,6 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
|
||||
goto bad;
|
||||
}
|
||||
/* Otherwise, give up and take any usable space. */
|
||||
/* FIXME: We should probably check for some minimum MDA size here. */
|
||||
else
|
||||
mda_size = limit - mda_start;
|
||||
|
||||
@@ -2242,6 +2242,12 @@ static int _text_pv_add_metadata_area(const struct format_type *fmt,
|
||||
mda_size, limit_name, limit);
|
||||
|
||||
if (mda_size) {
|
||||
if (mda_size < MDA_SIZE_MIN) {
|
||||
log_error("Metadata area size too small: %" PRIu64" bytes. "
|
||||
"It must be at least %u bytes.", mda_size, MDA_SIZE_MIN);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Wipe metadata area with zeroes. */
|
||||
if (!dev_set((struct device *) pv->dev, mda_start,
|
||||
(size_t) ((mda_size > wipe_size) ?
|
||||
|
||||
@@ -375,7 +375,7 @@ static int _read_segment(struct logical_volume *lv, const struct dm_config_node
|
||||
return 0;
|
||||
}
|
||||
|
||||
segtype_str = "striped";
|
||||
segtype_str = SEG_TYPE_NAME_STRIPED;
|
||||
|
||||
if (!dm_config_get_str(sn_child, "type", &segtype_str)) {
|
||||
log_error("Segment type must be a string.");
|
||||
|
||||
@@ -33,7 +33,7 @@ struct segment_type *init_free_segtype(struct cmd_context *cmd)
|
||||
return_NULL;
|
||||
|
||||
segtype->ops = &_freeseg_ops;
|
||||
segtype->name = "free";
|
||||
segtype->name = SEG_TYPE_NAME_FREE;
|
||||
segtype->flags = SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
@@ -337,7 +337,7 @@ static int _create_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
|
||||
dm_list_init(&lp.tags);
|
||||
|
||||
if (!(lp.segtype = get_segtype_from_string(vg->cmd, "striped")))
|
||||
if (!(lp.segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
lv = lv_create_single(vg, &lp);
|
||||
@@ -879,6 +879,9 @@ static int _lockd_all_lvs(struct cmd_context *cmd, struct volume_group *vg)
|
||||
struct lv_list *lvl;
|
||||
|
||||
dm_list_iterate_items(lvl, &vg->lvs) {
|
||||
if (!lockd_lv_uses_lock(lvl->lv))
|
||||
continue;
|
||||
|
||||
if (!lockd_lv(cmd, lvl->lv, "ex", 0)) {
|
||||
log_error("LV %s/%s must be inactive on all hosts.",
|
||||
vg->name, lvl->lv->name);
|
||||
@@ -2007,6 +2010,15 @@ int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (result == -EEXIST) {
|
||||
/*
|
||||
* This happens if lvchange tries to modify the LV with an ex
|
||||
* LV lock when the LV is already active with a sh LV lock.
|
||||
*/
|
||||
log_error("LV is already locked with incompatible mode: %s/%s", vg->name, lv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (result == -EMSGSIZE) {
|
||||
/* Another host probably extended lvmlock. */
|
||||
if (!refreshed++) {
|
||||
@@ -2549,7 +2561,7 @@ int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *lockd_running_lock_type(struct cmd_context *cmd)
|
||||
const char *lockd_running_lock_type(struct cmd_context *cmd, int *found_multiple)
|
||||
{
|
||||
daemon_reply reply;
|
||||
const char *lock_type = NULL;
|
||||
@@ -2571,10 +2583,9 @@ const char *lockd_running_lock_type(struct cmd_context *cmd)
|
||||
|
||||
switch (result) {
|
||||
case -EXFULL:
|
||||
log_error("lvmlockd found multiple lock managers, use --lock-type to select one.");
|
||||
*found_multiple = 1;
|
||||
break;
|
||||
case -ENOLCK:
|
||||
log_error("lvmlockd found no lock manager running.");
|
||||
break;
|
||||
case LOCK_TYPE_SANLOCK:
|
||||
log_debug("lvmlockd found sanlock");
|
||||
|
||||
@@ -89,7 +89,7 @@ int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg,
|
||||
int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *lv_name, struct id *lv_id, const char *lock_args);
|
||||
|
||||
const char *lockd_running_lock_type(struct cmd_context *cmd);
|
||||
const char *lockd_running_lock_type(struct cmd_context *cmd, int *found_multiple);
|
||||
|
||||
int handle_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
@@ -223,7 +223,7 @@ static inline int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline const char *lockd_running_lock_type(struct cmd_context *cmd)
|
||||
static inline const char *lockd_running_lock_type(struct cmd_context *cmd, int *found_multiple)
|
||||
{
|
||||
log_error("Using a shared lock type requires lvmlockd.");
|
||||
return NULL;
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
#include "lvm-string.h"
|
||||
#include "activate.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
/*
|
||||
* No locking
|
||||
*/
|
||||
|
||||
@@ -49,10 +49,7 @@ static size_t _lvm_errmsg_len = 0;
|
||||
|
||||
void init_log_fn(lvm2_log_fn_t log_fn)
|
||||
{
|
||||
if (log_fn)
|
||||
_lvm2_log_fn = log_fn;
|
||||
else
|
||||
_lvm2_log_fn = NULL;
|
||||
_lvm2_log_fn = log_fn;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
#ifndef _LVM_LOGGING_H
|
||||
#define _LVM_LOGGING_H
|
||||
|
||||
__attribute__ ((format(printf, 5, 6)))
|
||||
void print_log(int level, const char *file, int line, int dm_errno_or_class,
|
||||
const char *format, ...)
|
||||
__attribute__ ((format(printf, 5, 6)));
|
||||
const char *format, ...);
|
||||
|
||||
#define LOG_LINE(l, x...) \
|
||||
print_log(l, __FILE__, __LINE__ , 0, ## x)
|
||||
|
||||
@@ -261,7 +261,7 @@ struct logical_volume *lv_cache_create(struct logical_volume *pool_lv,
|
||||
if (lv_is_thin_pool(cache_lv))
|
||||
cache_lv = seg_lv(first_seg(cache_lv), 0); /* cache _tdata */
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "cache")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_CACHE)))
|
||||
return_NULL;
|
||||
|
||||
if (!insert_layer_for_lv(cmd, cache_lv, CACHE, "_corig"))
|
||||
@@ -407,7 +407,7 @@ int lv_cache_remove(struct logical_volume *cache_lv)
|
||||
|
||||
/* Replace 'error' with 'cache' segtype */
|
||||
cache_seg = first_seg(corigin_lv);
|
||||
if (!(cache_seg->segtype = get_segtype_from_string(corigin_lv->vg->cmd, "cache")))
|
||||
if (!(cache_seg->segtype = get_segtype_from_string(corigin_lv->vg->cmd, SEG_TYPE_NAME_CACHE)))
|
||||
return_0;
|
||||
|
||||
if (!(cache_seg->areas = dm_pool_zalloc(cache_lv->vg->vgmem, sizeof(*cache_seg->areas))))
|
||||
@@ -453,7 +453,7 @@ int lv_is_cache_origin(const struct logical_volume *lv)
|
||||
|
||||
static const char *_get_default_cache_policy(struct cmd_context *cmd)
|
||||
{
|
||||
const struct segment_type *segtype = get_segtype_from_string(cmd, "cache");
|
||||
const struct segment_type *segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_CACHE);
|
||||
unsigned attr = ~0;
|
||||
const char *def = NULL;
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ static struct utsname _utsname;
|
||||
static int _utsinit = 0;
|
||||
|
||||
static char *_format_pvsegs(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
int range_format)
|
||||
int range_format, int metadata_areas_only)
|
||||
{
|
||||
unsigned int s;
|
||||
const char *name = NULL;
|
||||
@@ -41,13 +41,19 @@ static char *_format_pvsegs(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (metadata_areas_only && (!seg_is_raid(seg) || lv_is_raid_metadata(seg->lv) || lv_is_raid_image(seg->lv)))
|
||||
goto out;
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
switch (seg_type(seg, s)) {
|
||||
switch (metadata_areas_only ? seg_metatype(seg, s) : seg_type(seg, s)) {
|
||||
case AREA_LV:
|
||||
name = seg_lv(seg, s)->name;
|
||||
extent = seg_le(seg, s);
|
||||
name = metadata_areas_only ? seg_metalv(seg, s)->name : seg_lv(seg, s)->name;
|
||||
extent = metadata_areas_only ? seg_le(seg, s) : 0;
|
||||
break;
|
||||
case AREA_PV:
|
||||
/* Raid metadata never uses PVs directly */
|
||||
if (metadata_areas_only)
|
||||
continue;
|
||||
name = dev_name(seg_dev(seg, s));
|
||||
extent = seg_pe(seg, s);
|
||||
break;
|
||||
@@ -79,7 +85,7 @@ static char *_format_pvsegs(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
|
||||
if (range_format) {
|
||||
if (dm_snprintf(extent_str, sizeof(extent_str),
|
||||
FMTu32, extent + seg->area_len - 1) < 0) {
|
||||
FMTu32, metadata_areas_only ? extent + seg_metalv(seg, s)->le_count - 1 : extent + seg->area_len - 1) < 0) {
|
||||
log_error("Extent number dm_snprintf failed");
|
||||
return NULL;
|
||||
}
|
||||
@@ -96,6 +102,7 @@ static char *_format_pvsegs(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (!dm_pool_grow_object(mem, "\0", 1)) {
|
||||
log_error("dm_pool_grow_object failed");
|
||||
return NULL;
|
||||
@@ -106,12 +113,22 @@ static char *_format_pvsegs(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
|
||||
char *lvseg_devices(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
{
|
||||
return _format_pvsegs(mem, seg, 0);
|
||||
return _format_pvsegs(mem, seg, 0, 0);
|
||||
}
|
||||
|
||||
char *lvseg_metadata_devices(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
{
|
||||
return _format_pvsegs(mem, seg, 0, 1);
|
||||
}
|
||||
|
||||
char *lvseg_seg_pe_ranges(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
{
|
||||
return _format_pvsegs(mem, seg, 1);
|
||||
return _format_pvsegs(mem, seg, 1, 0);
|
||||
}
|
||||
|
||||
char *lvseg_seg_metadata_le_ranges(struct dm_pool *mem, const struct lv_segment *seg)
|
||||
{
|
||||
return _format_pvsegs(mem, seg, 1, 1);
|
||||
}
|
||||
|
||||
char *lvseg_tags_dup(const struct lv_segment *seg)
|
||||
@@ -219,21 +236,37 @@ uint32_t lv_kernel_read_ahead(const struct logical_volume *lv)
|
||||
return info.read_ahead;
|
||||
}
|
||||
|
||||
static char *_do_lv_origin_dup(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int uuid)
|
||||
{
|
||||
struct logical_volume *origin;
|
||||
|
||||
|
||||
if (lv_is_cow(lv))
|
||||
origin = origin_from_cow(lv);
|
||||
else if (lv_is_cache(lv) && first_seg(lv)->origin)
|
||||
origin = first_seg(lv)->origin;
|
||||
else if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
|
||||
origin = first_seg(lv)->origin;
|
||||
else if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv)
|
||||
origin = first_seg(lv)->external_lv;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
if (uuid)
|
||||
return lv_uuid_dup(mem, origin);
|
||||
else
|
||||
return lv_name_dup(mem, origin);
|
||||
}
|
||||
|
||||
char *lv_origin_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
if (lv_is_cow(lv))
|
||||
return lv_name_dup(mem, origin_from_cow(lv));
|
||||
return _do_lv_origin_dup(mem, lv, 0);
|
||||
}
|
||||
|
||||
if (lv_is_cache(lv) && first_seg(lv)->origin)
|
||||
return lv_name_dup(mem, first_seg(lv)->origin);
|
||||
|
||||
if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
|
||||
return lv_name_dup(mem, first_seg(lv)->origin);
|
||||
|
||||
if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv)
|
||||
return lv_name_dup(mem, first_seg(lv)->external_lv);
|
||||
|
||||
return NULL;
|
||||
char *lv_origin_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_origin_dup(mem, lv, 1);
|
||||
}
|
||||
|
||||
char *lv_name_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
@@ -292,43 +325,112 @@ char *lv_modules_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
return tags_format_and_copy(mem, modules);
|
||||
}
|
||||
|
||||
char *lv_mirror_log_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
static char *_do_lv_mirror_log_dup(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int uuid)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
|
||||
dm_list_iterate_items(seg, &lv->segments)
|
||||
if (seg_is_mirrored(seg) && seg->log_lv)
|
||||
return dm_pool_strdup(mem, seg->log_lv->name);
|
||||
dm_list_iterate_items(seg, &lv->segments) {
|
||||
if (seg_is_mirrored(seg) && seg->log_lv) {
|
||||
if (uuid)
|
||||
return lv_uuid_dup(mem, seg->log_lv);
|
||||
else
|
||||
return lv_name_dup(mem, seg->log_lv);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *lv_mirror_log_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_mirror_log_dup(mem, lv, 0);
|
||||
}
|
||||
|
||||
char *lv_mirror_log_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_mirror_log_dup(mem, lv, 1);
|
||||
}
|
||||
|
||||
static char *_do_lv_pool_lv_dup(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int uuid)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
|
||||
dm_list_iterate_items(seg, &lv->segments) {
|
||||
if (seg->pool_lv &&
|
||||
(seg_is_thin_volume(seg) || seg_is_cache(seg))) {
|
||||
if (uuid)
|
||||
return lv_uuid_dup(mem, seg->pool_lv);
|
||||
else
|
||||
return lv_name_dup(mem, seg->pool_lv);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *lv_pool_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
return _do_lv_pool_lv_dup(mem, lv, 0);
|
||||
}
|
||||
|
||||
dm_list_iterate_items(seg, &lv->segments)
|
||||
if (seg->pool_lv &&
|
||||
(seg_is_thin_volume(seg) || seg_is_cache(seg)))
|
||||
return dm_pool_strdup(mem, seg->pool_lv->name);
|
||||
char *lv_pool_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_pool_lv_dup(mem, lv, 1);
|
||||
}
|
||||
|
||||
static char *_do_lv_data_lv_dup(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int uuid)
|
||||
{
|
||||
struct lv_segment *seg = (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) ?
|
||||
first_seg(lv) : NULL;
|
||||
|
||||
if (seg) {
|
||||
if (uuid)
|
||||
return lv_uuid_dup(mem, seg_lv(seg, 0));
|
||||
else
|
||||
return lv_name_dup(mem, seg_lv(seg, 0));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *lv_data_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg = (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) ?
|
||||
first_seg(lv) : NULL;
|
||||
|
||||
return seg ? dm_pool_strdup(mem, seg_lv(seg, 0)->name) : NULL;
|
||||
return _do_lv_data_lv_dup(mem, lv, 0);
|
||||
}
|
||||
|
||||
char *lv_metadata_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
char *lv_data_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_data_lv_dup(mem, lv, 1);
|
||||
}
|
||||
|
||||
|
||||
static char *_do_lv_metadata_lv_dup(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int uuid)
|
||||
{
|
||||
struct lv_segment *seg = (lv_is_thin_pool(lv) || lv_is_cache_pool(lv)) ?
|
||||
first_seg(lv) : NULL;
|
||||
|
||||
return seg ? dm_pool_strdup(mem, seg->metadata_lv->name) : NULL;
|
||||
if (seg) {
|
||||
if (uuid)
|
||||
return lv_uuid_dup(mem, seg->metadata_lv);
|
||||
else
|
||||
return lv_name_dup(mem, seg->metadata_lv);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *lv_metadata_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_metadata_lv_dup(mem, lv, 0);
|
||||
}
|
||||
|
||||
char *lv_metadata_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_metadata_lv_dup(mem, lv, 1);
|
||||
}
|
||||
|
||||
const char *lv_layer(const struct logical_volume *lv)
|
||||
@@ -358,7 +460,8 @@ int lv_kernel_major(const struct logical_volume *lv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *lv_convert_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
static char *_do_lv_convert_lv_dup(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int uuid)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
|
||||
@@ -367,17 +470,32 @@ char *lv_convert_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
|
||||
/* Temporary mirror is always area_num == 0 */
|
||||
if (seg_type(seg, 0) == AREA_LV &&
|
||||
is_temporary_mirror_layer(seg_lv(seg, 0)))
|
||||
return dm_pool_strdup(mem, seg_lv(seg, 0)->name);
|
||||
is_temporary_mirror_layer(seg_lv(seg, 0))) {
|
||||
if (uuid)
|
||||
return lv_uuid_dup(mem, seg_lv(seg, 0));
|
||||
else
|
||||
return lv_name_dup(mem, seg_lv(seg, 0));
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *lv_move_pv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
char *lv_convert_lv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_convert_lv_dup(mem, lv, 0);
|
||||
}
|
||||
|
||||
char *lv_convert_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_convert_lv_dup(mem, lv, 1);
|
||||
}
|
||||
|
||||
static char *_do_lv_move_pv_dup(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
int uuid)
|
||||
{
|
||||
struct logical_volume *mimage0_lv;
|
||||
struct lv_segment *seg;
|
||||
const struct device *dev;
|
||||
struct pv_segment *pvseg;
|
||||
|
||||
dm_list_iterate_items(seg, &lv->segments) {
|
||||
if (seg->status & PVMOVE) {
|
||||
@@ -388,17 +506,30 @@ char *lv_move_pv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
"Bad pvmove structure");
|
||||
return NULL;
|
||||
}
|
||||
dev = seg_dev(first_seg(mimage0_lv), 0);
|
||||
pvseg = seg_pvseg(first_seg(mimage0_lv), 0);
|
||||
} else /* Segment pvmove */
|
||||
dev = seg_dev(seg, 0);
|
||||
pvseg = seg_pvseg(seg, 0);
|
||||
|
||||
return dm_pool_strdup(mem, dev_name(dev));
|
||||
if (uuid)
|
||||
return pv_uuid_dup(mem, pvseg->pv);
|
||||
else
|
||||
return pv_name_dup(mem, pvseg->pv);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *lv_move_pv_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_move_pv_dup(mem, lv, 0);
|
||||
}
|
||||
|
||||
char *lv_move_pv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return _do_lv_move_pv_dup(mem, lv, 1);
|
||||
}
|
||||
|
||||
uint64_t lv_origin_size(const struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
@@ -479,9 +610,9 @@ char *lv_dmpath_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
return repstr;
|
||||
}
|
||||
|
||||
char *lv_uuid_dup(const struct logical_volume *lv)
|
||||
char *lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv)
|
||||
{
|
||||
return id_format_and_copy(lv->vg->vgmem, &lv->lvid.id[1]);
|
||||
return id_format_and_copy(mem ? mem : lv->vg->vgmem, &lv->lvid.id[1]);
|
||||
}
|
||||
|
||||
char *lv_tags_dup(const struct logical_volume *lv)
|
||||
@@ -534,6 +665,7 @@ int lv_raid_image_in_sync(const struct logical_volume *lv)
|
||||
|
||||
if ((seg = first_seg(lv)))
|
||||
raid_seg = get_only_segment_using_this_lv(seg->lv);
|
||||
|
||||
if (!raid_seg) {
|
||||
log_error("Failed to find RAID segment for %s", lv->name);
|
||||
return 0;
|
||||
|
||||
@@ -35,8 +35,8 @@ struct logical_volume {
|
||||
int32_t major;
|
||||
int32_t minor;
|
||||
|
||||
uint64_t size; /* Sectors */
|
||||
uint32_t le_count;
|
||||
uint64_t size; /* Sectors visible */
|
||||
uint32_t le_count; /* Logical extents visible */
|
||||
|
||||
uint32_t origin_count;
|
||||
uint32_t external_count;
|
||||
@@ -62,25 +62,34 @@ uint64_t lv_size(const struct logical_volume *lv);
|
||||
uint64_t lv_metadata_size(const struct logical_volume *lv);
|
||||
char *lv_attr_dup_with_info_and_seg_status(struct dm_pool *mem, const struct lv_with_info_and_seg_status *lvdm);
|
||||
char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_uuid_dup(const struct logical_volume *lv);
|
||||
char *lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_tags_dup(const struct logical_volume *lv);
|
||||
char *lv_path_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_dmpath_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
uint64_t lv_origin_size(const struct logical_volume *lv);
|
||||
char *lv_move_pv_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_move_pv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_convert_lv_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_convert_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
int lv_kernel_major(const struct logical_volume *lv);
|
||||
int lv_kernel_minor(const struct logical_volume *lv);
|
||||
char *lv_mirror_log_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_mirror_log_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_data_lv_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_data_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_metadata_lv_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_metadata_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_pool_lv_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_pool_lv_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
|
||||
char *lv_modules_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_name_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_fullname_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
struct logical_volume *lv_parent(const struct logical_volume *lv);
|
||||
char *lv_parent_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_origin_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
char *lv_origin_uuid_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
|
||||
uint32_t lv_kernel_read_ahead(const struct logical_volume *lv);
|
||||
const char *lvseg_name(const struct lv_segment *seg);
|
||||
uint64_t lvseg_start(const struct lv_segment *seg);
|
||||
@@ -92,7 +101,9 @@ char *lvseg_cachemode_dup(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lvseg_monitor_dup(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lvseg_tags_dup(const struct lv_segment *seg);
|
||||
char *lvseg_devices(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lvseg_metadata_devices(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lvseg_seg_pe_ranges(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lvseg_seg_metadata_le_ranges(struct dm_pool *mem, const struct lv_segment *seg);
|
||||
char *lv_time_dup(struct dm_pool *mem, const struct logical_volume *lv, int iso_mode);
|
||||
char *lv_host_dup(struct dm_pool *mem, const struct logical_volume *lv);
|
||||
int lv_set_creation(struct logical_volume *lv,
|
||||
|
||||
@@ -129,6 +129,8 @@ enum {
|
||||
LV_TYPE_RAID6_ZR,
|
||||
LV_TYPE_RAID6_NR,
|
||||
LV_TYPE_RAID6_NC,
|
||||
LV_TYPE_LOCKD,
|
||||
LV_TYPE_SANLOCK
|
||||
};
|
||||
|
||||
static const char *_lv_type_names[] = {
|
||||
@@ -173,6 +175,8 @@ static const char *_lv_type_names[] = {
|
||||
[LV_TYPE_RAID6_ZR] = SEG_TYPE_NAME_RAID6_ZR,
|
||||
[LV_TYPE_RAID6_NR] = SEG_TYPE_NAME_RAID6_NR,
|
||||
[LV_TYPE_RAID6_NC] = SEG_TYPE_NAME_RAID6_NC,
|
||||
[LV_TYPE_LOCKD] = "lockd",
|
||||
[LV_TYPE_SANLOCK] = "sanlock",
|
||||
};
|
||||
|
||||
static int _lv_layout_and_role_mirror(struct dm_pool *mem,
|
||||
@@ -224,7 +228,7 @@ static int _lv_layout_and_role_raid(struct dm_pool *mem,
|
||||
int *public_lv)
|
||||
{
|
||||
int top_level = 0;
|
||||
const char *seg_name;
|
||||
const struct segment_type *segtype;
|
||||
|
||||
/* non-top-level LVs */
|
||||
if (lv_is_raid_image(lv)) {
|
||||
@@ -251,45 +255,45 @@ static int _lv_layout_and_role_raid(struct dm_pool *mem,
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID]))
|
||||
goto_bad;
|
||||
|
||||
seg_name = first_seg(lv)->segtype->name;
|
||||
segtype = first_seg(lv)->segtype;
|
||||
|
||||
if (!strcmp(seg_name, SEG_TYPE_NAME_RAID1)) {
|
||||
if (segtype_is_raid1(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID1]))
|
||||
goto_bad;
|
||||
} else if (!strcmp(seg_name, SEG_TYPE_NAME_RAID10)) {
|
||||
} else if (segtype_is_raid10(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID10]))
|
||||
goto_bad;
|
||||
} else if (!strcmp(seg_name, SEG_TYPE_NAME_RAID4)) {
|
||||
} else if (segtype_is_raid4(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID4]))
|
||||
goto_bad;
|
||||
} else if (!strncmp(seg_name, SEG_TYPE_NAME_RAID5, strlen(SEG_TYPE_NAME_RAID5))) {
|
||||
} else if (segtype_is_any_raid5(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID5]))
|
||||
goto_bad;
|
||||
|
||||
if (!strcmp(seg_name, SEG_TYPE_NAME_RAID5_LA)) {
|
||||
if (segtype_is_raid5_la(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID5_LA]))
|
||||
goto_bad;
|
||||
} else if (!strcmp(seg_name, SEG_TYPE_NAME_RAID5_RA)) {
|
||||
} else if (segtype_is_raid5_ra(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID5_RA]))
|
||||
goto_bad;
|
||||
} else if (!strcmp(seg_name, SEG_TYPE_NAME_RAID5_LS)) {
|
||||
} else if (segtype_is_raid5_ls(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID5_LS]))
|
||||
goto_bad;
|
||||
} else if (!strcmp(seg_name, SEG_TYPE_NAME_RAID5_RS)) {
|
||||
} else if (segtype_is_raid5_rs(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID5_RS]))
|
||||
goto_bad;
|
||||
}
|
||||
} else if (!strncmp(seg_name, SEG_TYPE_NAME_RAID6, strlen(SEG_TYPE_NAME_RAID6))) {
|
||||
} else if (segtype_is_any_raid6(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID6]))
|
||||
goto_bad;
|
||||
|
||||
if (!strcmp(seg_name, SEG_TYPE_NAME_RAID6_ZR)) {
|
||||
if (segtype_is_raid6_zr(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID6_ZR]))
|
||||
goto_bad;
|
||||
} else if (!strcmp(seg_name, SEG_TYPE_NAME_RAID6_NR)) {
|
||||
} else if (segtype_is_raid6_nr(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID6_NR]))
|
||||
goto_bad;
|
||||
} else if (!strcmp(seg_name, SEG_TYPE_NAME_RAID6_NC)) {
|
||||
} else if (segtype_is_raid6_nc(segtype)) {
|
||||
if (!str_list_add_no_dup_check(mem, layout, _lv_type_names[LV_TYPE_RAID6_NC]))
|
||||
goto_bad;
|
||||
}
|
||||
@@ -505,6 +509,13 @@ int lv_layout_and_role(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
if (!_lv_layout_and_role_thick_origin_snapshot(mem, lv, *layout, *role, &public_lv))
|
||||
goto_bad;
|
||||
|
||||
if (lv_is_lockd_sanlock_lv(lv)) {
|
||||
if (!str_list_add_no_dup_check(mem, *role, _lv_type_names[LV_TYPE_LOCKD]) ||
|
||||
!str_list_add_no_dup_check(mem, *role, _lv_type_names[LV_TYPE_SANLOCK]))
|
||||
goto_bad;
|
||||
public_lv = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If layout not yet determined, it must be either
|
||||
* linear or striped or mixture of these two.
|
||||
@@ -780,7 +791,7 @@ int get_default_region_size(struct cmd_context *cmd)
|
||||
|
||||
if (region_size & (region_size - 1)) {
|
||||
region_size = _round_down_pow2(region_size);
|
||||
log_verbose("Reducing mirror region size to %u kiB (power of 2).",
|
||||
log_verbose("Reducing region size to %u kiB (power of 2).",
|
||||
region_size / 2);
|
||||
}
|
||||
|
||||
@@ -930,7 +941,7 @@ dm_percent_t copy_percent(const struct logical_volume *lv)
|
||||
dm_list_iterate_items(seg, &lv->segments) {
|
||||
denominator += seg->area_len;
|
||||
|
||||
/* FIXME Generalise name of 'extents_copied' field */
|
||||
/* FIXME Generalise name of 'extents_copied' field */
|
||||
if ((seg_is_raid(seg) || seg_is_mirrored(seg)) &&
|
||||
(seg->area_count > 1))
|
||||
numerator += seg->extents_copied;
|
||||
@@ -938,7 +949,27 @@ dm_percent_t copy_percent(const struct logical_volume *lv)
|
||||
numerator += seg->area_len;
|
||||
}
|
||||
|
||||
return denominator ? dm_make_percent( numerator, denominator ) : 100.0;
|
||||
return denominator ? dm_make_percent(numerator, denominator) : 100.0;
|
||||
}
|
||||
|
||||
/* Round up extents to next stripe boundary for number of stripes */
|
||||
static uint32_t _round_to_stripe_boundary(struct volume_group *vg, uint32_t extents,
|
||||
uint32_t stripes, int extend)
|
||||
{
|
||||
uint32_t size_rest, new_extents = extents;
|
||||
|
||||
if (!stripes)
|
||||
return extents;
|
||||
|
||||
/* Round up extents to stripe divisible amount */
|
||||
if ((size_rest = extents % stripes)) {
|
||||
new_extents += extend ? stripes - size_rest : -size_rest;
|
||||
log_print_unless_silent("Rounding size %s (%d extents) up to stripe boundary size %s (%d extents).",
|
||||
display_size(vg->cmd, extents * vg->extent_size), extents,
|
||||
display_size(vg->cmd, new_extents * vg->extent_size), new_extents);
|
||||
}
|
||||
|
||||
return new_extents;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1013,7 +1044,7 @@ struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
|
||||
struct lv_segment *seg;
|
||||
const struct segment_type *segtype;
|
||||
|
||||
segtype = get_segtype_from_string(lv->vg->cmd, "snapshot");
|
||||
segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_SNAPSHOT);
|
||||
if (!segtype) {
|
||||
log_error("Failed to find snapshot segtype");
|
||||
return NULL;
|
||||
@@ -1037,6 +1068,7 @@ static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t
|
||||
uint32_t area_reduction, int with_discard)
|
||||
{
|
||||
struct lv_segment *cache_seg;
|
||||
struct logical_volume *lv = seg_lv(seg, s);
|
||||
|
||||
if (seg_type(seg, s) == AREA_UNASSIGNED)
|
||||
return 1;
|
||||
@@ -1054,10 +1086,10 @@ static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lv_is_mirror_image(seg_lv(seg, s)) ||
|
||||
lv_is_thin_pool_data(seg_lv(seg, s)) ||
|
||||
lv_is_cache_pool_data(seg_lv(seg, s))) {
|
||||
if (!lv_reduce(seg_lv(seg, s), area_reduction))
|
||||
if (lv_is_mirror_image(lv) ||
|
||||
lv_is_thin_pool_data(lv) ||
|
||||
lv_is_cache_pool_data(lv)) {
|
||||
if (!lv_reduce(lv, area_reduction))
|
||||
return_0; /* FIXME: any upper level reporting */
|
||||
return 1;
|
||||
}
|
||||
@@ -1071,20 +1103,20 @@ static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (lv_is_raid_image(seg_lv(seg, s))) {
|
||||
if (lv_is_raid_image(lv)) {
|
||||
/*
|
||||
* FIXME: Use lv_reduce not lv_remove
|
||||
* We use lv_remove for now, because I haven't figured out
|
||||
* why lv_reduce won't remove the LV.
|
||||
lv_reduce(seg_lv(seg, s), area_reduction);
|
||||
lv_reduce(lv, area_reduction);
|
||||
*/
|
||||
if (area_reduction != seg->area_len) {
|
||||
log_error("Unable to reduce RAID LV - operation not implemented.");
|
||||
return_0;
|
||||
} else {
|
||||
if (!lv_remove(seg_lv(seg, s))) {
|
||||
if (!lv_remove(lv)) {
|
||||
log_error("Failed to remove RAID image %s",
|
||||
seg_lv(seg, s)->name);
|
||||
lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1105,9 +1137,9 @@ static int _release_and_discard_lv_segment_area(struct lv_segment *seg, uint32_t
|
||||
log_very_verbose("Remove %s:%" PRIu32 "[%" PRIu32 "] from "
|
||||
"the top of LV %s:%" PRIu32,
|
||||
seg->lv->name, seg->le, s,
|
||||
seg_lv(seg, s)->name, seg_le(seg, s));
|
||||
lv->name, seg_le(seg, s));
|
||||
|
||||
if (!remove_seg_from_segs_using_this_lv(seg_lv(seg, s), seg))
|
||||
if (!remove_seg_from_segs_using_this_lv(lv, seg))
|
||||
return_0;
|
||||
seg_lv(seg, s) = NULL;
|
||||
seg_le(seg, s) = 0;
|
||||
@@ -1243,6 +1275,51 @@ static int _lv_segment_add_areas(struct logical_volume *lv,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t _calc_area_multiple(const struct segment_type *segtype,
|
||||
const uint32_t area_count,
|
||||
const uint32_t stripes)
|
||||
{
|
||||
if (!area_count)
|
||||
return 1;
|
||||
|
||||
/* Striped */
|
||||
if (segtype_is_striped(segtype))
|
||||
return area_count;
|
||||
|
||||
/* Parity RAID (e.g. RAID 4/5/6) */
|
||||
if (segtype_is_raid(segtype) && segtype->parity_devs) {
|
||||
/*
|
||||
* As articulated in _alloc_init, we can tell by
|
||||
* the area_count whether a replacement drive is
|
||||
* being allocated; and if this is the case, then
|
||||
* there is no area_multiple that should be used.
|
||||
*/
|
||||
if (area_count <= segtype->parity_devs)
|
||||
return 1;
|
||||
|
||||
return area_count - segtype->parity_devs;
|
||||
}
|
||||
|
||||
/*
|
||||
* RAID10 - only has 2-way mirror right now.
|
||||
* If we are to move beyond 2-way RAID10, then
|
||||
* the 'stripes' argument will always need to
|
||||
* be given.
|
||||
*/
|
||||
if (!strcmp(segtype->name, _lv_type_names[LV_TYPE_RAID10])) {
|
||||
if (!stripes)
|
||||
return area_count / 2;
|
||||
return stripes;
|
||||
}
|
||||
|
||||
/* Mirrored stripes */
|
||||
if (stripes)
|
||||
return stripes;
|
||||
|
||||
/* Mirrored */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reduce the size of an lv_segment. New size can be zero.
|
||||
*/
|
||||
@@ -1393,7 +1470,7 @@ int replace_lv_with_error_segment(struct logical_volume *lv)
|
||||
|
||||
/* FIXME Check for any attached LVs that will become orphans e.g. mirror logs */
|
||||
|
||||
if (!lv_add_virtual_segment(lv, 0, len, get_segtype_from_string(lv->vg->cmd, "error")))
|
||||
if (!lv_add_virtual_segment(lv, 0, len, get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_ERROR)))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
@@ -1460,10 +1537,10 @@ struct alloc_handle {
|
||||
struct dm_pool *mem;
|
||||
|
||||
alloc_policy_t alloc; /* Overall policy */
|
||||
int approx_alloc; /* get as much as possible up to new_extents */
|
||||
int approx_alloc; /* get as much as possible up to new_extents */
|
||||
uint32_t new_extents; /* Number of new extents required */
|
||||
uint32_t area_count; /* Number of parallel areas */
|
||||
uint32_t parity_count; /* Adds to area_count, but not area_multiple */
|
||||
uint32_t parity_count; /* Adds to area_count, but not area_multiple */
|
||||
uint32_t area_multiple; /* seg->len = area_len * area_multiple */
|
||||
uint32_t log_area_count; /* Number of parallel logs */
|
||||
uint32_t metadata_area_count; /* Number of parallel metadata areas */
|
||||
@@ -1498,50 +1575,6 @@ struct alloc_handle {
|
||||
struct dm_list alloced_areas[0];
|
||||
};
|
||||
|
||||
static uint32_t _calc_area_multiple(const struct segment_type *segtype,
|
||||
const uint32_t area_count,
|
||||
const uint32_t stripes)
|
||||
{
|
||||
if (!area_count)
|
||||
return 1;
|
||||
|
||||
/* Striped */
|
||||
if (segtype_is_striped(segtype))
|
||||
return area_count;
|
||||
|
||||
/* Parity RAID (e.g. RAID 4/5/6) */
|
||||
if (segtype_is_raid(segtype) && segtype->parity_devs) {
|
||||
/*
|
||||
* As articulated in _alloc_init, we can tell by
|
||||
* the area_count whether a replacement drive is
|
||||
* being allocated; and if this is the case, then
|
||||
* there is no area_multiple that should be used.
|
||||
*/
|
||||
if (area_count <= segtype->parity_devs)
|
||||
return 1;
|
||||
return area_count - segtype->parity_devs;
|
||||
}
|
||||
|
||||
/*
|
||||
* RAID10 - only has 2-way mirror right now.
|
||||
* If we are to move beyond 2-way RAID10, then
|
||||
* the 'stripes' argument will always need to
|
||||
* be given.
|
||||
*/
|
||||
if (!strcmp(segtype->name, _lv_type_names[LV_TYPE_RAID10])) {
|
||||
if (!stripes)
|
||||
return area_count / 2;
|
||||
return stripes;
|
||||
}
|
||||
|
||||
/* Mirrored stripes */
|
||||
if (stripes)
|
||||
return stripes;
|
||||
|
||||
/* Mirrored */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns log device size in extents, algorithm from kernel code
|
||||
*/
|
||||
@@ -1583,7 +1616,7 @@ static int _sufficient_pes_free(struct alloc_handle *ah, struct dm_list *pvms,
|
||||
{
|
||||
uint32_t area_extents_needed = (extents_still_needed - allocated) * ah->area_count / ah->area_multiple;
|
||||
uint32_t parity_extents_needed = (extents_still_needed - allocated) * ah->parity_count / ah->area_multiple;
|
||||
uint32_t metadata_extents_needed = (ah->alloc_and_split_meta) ? 0 : ah->metadata_area_count * RAID_METADATA_AREA_LEN; /* One each */
|
||||
uint32_t metadata_extents_needed = ah->alloc_and_split_meta ? 0 : ah->metadata_area_count * RAID_METADATA_AREA_LEN; /* One each */
|
||||
uint32_t total_extents_needed = area_extents_needed + parity_extents_needed + metadata_extents_needed;
|
||||
uint32_t free_pes = pv_maps_size(pvms);
|
||||
|
||||
@@ -1726,9 +1759,9 @@ static int _setup_alloced_segment(struct logical_volume *lv, uint64_t status,
|
||||
struct lv_segment *seg;
|
||||
|
||||
area_multiple = _calc_area_multiple(segtype, area_count, 0);
|
||||
extents = aa[0].len * area_multiple;
|
||||
|
||||
if (!(seg = alloc_lv_segment(segtype, lv, lv->le_count,
|
||||
aa[0].len * area_multiple,
|
||||
if (!(seg = alloc_lv_segment(segtype, lv, lv->le_count, extents,
|
||||
status, stripe_size, NULL,
|
||||
area_count,
|
||||
aa[0].len, 0u, region_size, 0u, NULL))) {
|
||||
@@ -1744,7 +1777,7 @@ static int _setup_alloced_segment(struct logical_volume *lv, uint64_t status,
|
||||
|
||||
extents = aa[0].len * area_multiple;
|
||||
lv->le_count += extents;
|
||||
lv->size += (uint64_t) extents *lv->vg->extent_size;
|
||||
lv->size += (uint64_t) extents * lv->vg->extent_size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1910,7 +1943,7 @@ static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
*max_seg_len = remaining_seg_len;
|
||||
|
||||
area_multiple = _calc_area_multiple(seg->segtype, seg->area_count, 0);
|
||||
area_len = remaining_seg_len / area_multiple ? : 1;
|
||||
area_len = (remaining_seg_len / area_multiple) ? : 1;
|
||||
|
||||
/* For striped mirrors, all the areas are counted, through the mirror layer */
|
||||
if (top_level_area_index == -1)
|
||||
@@ -2956,7 +2989,7 @@ static int _allocate(struct alloc_handle *ah,
|
||||
|
||||
if (ah->area_multiple > 1 &&
|
||||
(ah->new_extents - alloc_state.allocated) % ah->area_multiple) {
|
||||
log_error("Number of extents requested (%d) needs to be divisible by %d.",
|
||||
log_error("Number of extents requested (" FMTu32 ") needs to be divisible by " FMTu32 ".",
|
||||
ah->new_extents - alloc_state.allocated,
|
||||
ah->area_multiple);
|
||||
return 0;
|
||||
@@ -3401,7 +3434,7 @@ static struct lv_segment *_convert_seg_to_mirror(struct lv_segment *seg,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(newseg = alloc_lv_segment(get_segtype_from_string(seg->lv->vg->cmd, "mirror"),
|
||||
if (!(newseg = alloc_lv_segment(get_segtype_from_string(seg->lv->vg->cmd, SEG_TYPE_NAME_MIRROR),
|
||||
seg->lv, seg->le, seg->len,
|
||||
seg->status, seg->stripe_size,
|
||||
log_lv,
|
||||
@@ -3494,7 +3527,7 @@ int lv_add_segmented_mirror_image(struct alloc_handle *ah,
|
||||
if (!lv_add_mirror_lvs(lv, ©_lv, 1, MIRROR_IMAGE, region_size))
|
||||
return_0;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
dm_list_iterate_items(aa, &ah->alloced_areas[0]) {
|
||||
@@ -3608,7 +3641,7 @@ int lv_add_mirror_lvs(struct logical_volume *lv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
mirror_segtype = get_segtype_from_string(lv->vg->cmd, "mirror");
|
||||
mirror_segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_MIRROR);
|
||||
if (seg->segtype != mirror_segtype)
|
||||
if (!(seg = _convert_seg_to_mirror(seg, region_size, NULL)))
|
||||
return_0;
|
||||
@@ -3667,8 +3700,7 @@ int lv_add_log_segment(struct alloc_handle *ah, uint32_t first_area,
|
||||
{
|
||||
|
||||
return lv_add_segment(ah, ah->area_count + first_area, 1, log_lv,
|
||||
get_segtype_from_string(log_lv->vg->cmd,
|
||||
"striped"),
|
||||
get_segtype_from_string(log_lv->vg->cmd, SEG_TYPE_NAME_STRIPED),
|
||||
0, status, 0);
|
||||
}
|
||||
|
||||
@@ -3765,23 +3797,23 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah,
|
||||
{
|
||||
const struct segment_type *segtype;
|
||||
struct logical_volume *sub_lv, *meta_lv;
|
||||
struct lv_segment *seg;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
uint32_t fa, s;
|
||||
int clear_metadata = 0;
|
||||
|
||||
segtype = get_segtype_from_string(lv->vg->cmd, "striped");
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* The component devices of a "striped" LV all go in the same
|
||||
* LV. However, RAID has an LV for each device - making the
|
||||
* 'stripes' and 'stripe_size' parameters meaningless.
|
||||
*/
|
||||
if (seg_is_raid(first_seg(lv))) {
|
||||
if (seg_is_raid(seg)) {
|
||||
stripes = 1;
|
||||
stripe_size = 0;
|
||||
}
|
||||
|
||||
seg = first_seg(lv);
|
||||
for (fa = first_area, s = 0; s < seg->area_count; s++) {
|
||||
if (is_temporary_mirror_layer(seg_lv(seg, s))) {
|
||||
if (!_lv_extend_layered_lv(ah, seg_lv(seg, s), extents,
|
||||
@@ -4392,6 +4424,25 @@ static int _fsadm_cmd(struct cmd_context *cmd,
|
||||
return exec_cmd(cmd, argv, status, 1);
|
||||
}
|
||||
|
||||
static int _adjust_amount(dm_percent_t percent, int policy_threshold, int *policy_amount)
|
||||
{
|
||||
if (!(DM_PERCENT_0 < percent && percent <= DM_PERCENT_100) ||
|
||||
percent <= (policy_threshold * DM_PERCENT_1))
|
||||
return 0;
|
||||
/*
|
||||
* Evaluate the minimal amount needed to get bellow threshold.
|
||||
* Keep using DM_PERCENT_1 units for better precision.
|
||||
* Round-up to needed percentage value
|
||||
*/
|
||||
percent = (percent/policy_threshold + (DM_PERCENT_1 - 1) / 100) / (DM_PERCENT_1 / 100) - 100;
|
||||
|
||||
/* Use it if current policy amount is smaller */
|
||||
if (*policy_amount < percent)
|
||||
*policy_amount = percent;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _adjust_policy_params(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, struct lvresize_params *lp)
|
||||
{
|
||||
@@ -4401,23 +4452,34 @@ static int _adjust_policy_params(struct cmd_context *cmd,
|
||||
if (lv_is_thin_pool(lv)) {
|
||||
policy_threshold =
|
||||
find_config_tree_int(cmd, activation_thin_pool_autoextend_threshold_CFG,
|
||||
lv_config_profile(lv)) * DM_PERCENT_1;
|
||||
lv_config_profile(lv));
|
||||
policy_amount =
|
||||
find_config_tree_int(cmd, activation_thin_pool_autoextend_percent_CFG,
|
||||
lv_config_profile(lv));
|
||||
if (!policy_amount && policy_threshold < DM_PERCENT_100) {
|
||||
log_error("Can't extend thin pool %s, autoextend is set to 0%%.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
if (policy_threshold < 50) {
|
||||
log_warn("WARNING: Thin pool autoextend threshold %d%% is set below "
|
||||
"minimum supported 50%%.", policy_threshold);
|
||||
policy_threshold = 50;
|
||||
}
|
||||
} else {
|
||||
policy_threshold =
|
||||
find_config_tree_int(cmd, activation_snapshot_autoextend_threshold_CFG, NULL) * DM_PERCENT_1;
|
||||
find_config_tree_int(cmd, activation_snapshot_autoextend_threshold_CFG, NULL);
|
||||
policy_amount =
|
||||
find_config_tree_int(cmd, activation_snapshot_autoextend_percent_CFG, NULL);
|
||||
if (policy_threshold < 50) {
|
||||
log_warn("WARNING: Snapshot autoextend threshold %d%% is set bellow "
|
||||
"minimal supported value 50%%.", policy_threshold);
|
||||
policy_threshold = 50;
|
||||
}
|
||||
}
|
||||
|
||||
if (policy_threshold >= DM_PERCENT_100)
|
||||
if (!policy_amount && policy_threshold < 100) {
|
||||
log_error("Can't extend %s with %s autoextend percent set to 0%%.",
|
||||
display_lvname(lv), first_seg(lv)->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (policy_threshold >= 100)
|
||||
return 1; /* nothing to do */
|
||||
|
||||
if (!lv_is_active_locally(lv)) {
|
||||
@@ -4429,30 +4491,26 @@ static int _adjust_policy_params(struct cmd_context *cmd,
|
||||
if (lv_is_thin_pool(lv)) {
|
||||
if (!lv_thin_pool_percent(lv, 1, &percent))
|
||||
return_0;
|
||||
if ((DM_PERCENT_0 < percent && percent <= DM_PERCENT_100) &&
|
||||
(percent > policy_threshold)) {
|
||||
if (_adjust_amount(percent, policy_threshold, &policy_amount)) {
|
||||
if (!thin_pool_feature_supported(lv, THIN_FEATURE_METADATA_RESIZE)) {
|
||||
log_error_once("Online metadata resize for %s/%s is not supported.",
|
||||
lv->vg->name, lv->name);
|
||||
log_error_once("Online metadata resize for %s is not supported.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
lp->poolmetadatasize = (first_seg(lv)->metadata_lv->size *
|
||||
policy_amount + 99) / 100;
|
||||
lp->poolmetadatasign = SIGN_PLUS;
|
||||
}
|
||||
|
||||
if (!lv_thin_pool_percent(lv, 0, &percent))
|
||||
return_0;
|
||||
if (!(DM_PERCENT_0 < percent && percent <= DM_PERCENT_100) ||
|
||||
percent <= policy_threshold)
|
||||
return 1;
|
||||
} else {
|
||||
if (!lv_snapshot_percent(lv, &percent))
|
||||
return_0;
|
||||
if (!(DM_PERCENT_0 < percent && percent <= DM_PERCENT_100) || percent <= policy_threshold)
|
||||
return 1; /* nothing to do */
|
||||
}
|
||||
|
||||
if (!_adjust_amount(percent, policy_threshold, &policy_amount))
|
||||
return 1; /* nothing to do */
|
||||
|
||||
lp->extents = policy_amount;
|
||||
lp->sizeargs = (lp->extents) ? 1 : 0;
|
||||
|
||||
@@ -4547,7 +4605,7 @@ static int _lvresize_poolmetadata(struct cmd_context *cmd, struct volume_group *
|
||||
struct dm_list *pvh)
|
||||
{
|
||||
struct logical_volume *lv = first_seg(pool_lv)->metadata_lv;
|
||||
alloc_policy_t alloc = lp->ac_alloc ?: lv->alloc;
|
||||
alloc_policy_t alloc = lp->ac_alloc ? : lv->alloc;
|
||||
struct lv_segment *mseg = last_seg(lv);
|
||||
uint32_t seg_mirrors = lv_mirror_count(lv);
|
||||
|
||||
@@ -5156,7 +5214,7 @@ static struct logical_volume *_lvresize_volume(struct cmd_context *cmd,
|
||||
/* Switch to layered LV resizing */
|
||||
lv = seg_lv(seg, 0);
|
||||
}
|
||||
alloc = lp->ac_alloc ?: lv->alloc;
|
||||
alloc = lp->ac_alloc ? : lv->alloc;
|
||||
|
||||
if ((lp->resize == LV_REDUCE) && lp->argc)
|
||||
log_print_unless_silent("Ignoring PVs on command line when reducing.");
|
||||
@@ -5173,7 +5231,7 @@ static struct logical_volume *_lvresize_volume(struct cmd_context *cmd,
|
||||
log_error("Filesystem check failed.");
|
||||
return NULL;
|
||||
}
|
||||
/* some filesystems supports online resize */
|
||||
/* some filesystems support online resize */
|
||||
}
|
||||
|
||||
/* FIXME forks here */
|
||||
@@ -6209,7 +6267,7 @@ int remove_layers_for_segments(struct cmd_context *cmd,
|
||||
|
||||
/* Replace mirror with error segment */
|
||||
if (!(lseg->segtype =
|
||||
get_segtype_from_string(lv->vg->cmd, "error"))) {
|
||||
get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_ERROR))) {
|
||||
log_error("Missing error segtype");
|
||||
return 0;
|
||||
}
|
||||
@@ -6343,7 +6401,7 @@ int remove_layer_from_lv(struct logical_volume *lv,
|
||||
return_0;
|
||||
|
||||
/* Replace the empty layer with error segment */
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "error")))
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_ERROR)))
|
||||
return_0;
|
||||
if (!lv_add_virtual_segment(layer_lv, 0, parent_lv->le_count, segtype))
|
||||
return_0;
|
||||
@@ -6407,7 +6465,7 @@ struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
|
||||
if (lv_is_active(lv_where) && strstr(name, "_mimagetmp")) {
|
||||
log_very_verbose("Creating transient LV %s for mirror conversion in VG %s.", name, lv_where->vg->name);
|
||||
|
||||
segtype = get_segtype_from_string(cmd, "error");
|
||||
segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_ERROR);
|
||||
|
||||
if (!lv_add_virtual_segment(layer_lv, 0, lv_where->le_count, segtype)) {
|
||||
log_error("Creation of transient LV %s for mirror conversion in VG %s failed.", name, lv_where->vg->name);
|
||||
@@ -6455,7 +6513,7 @@ struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
|
||||
if (!move_lv_segments(layer_lv, lv_where, 0, 0))
|
||||
return_NULL;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_NULL;
|
||||
|
||||
/* allocate a new linear segment */
|
||||
@@ -6505,7 +6563,7 @@ static int _extend_layer_lv_for_segment(struct logical_volume *layer_lv,
|
||||
if (seg_type(seg, s) != AREA_PV && seg_type(seg, s) != AREA_LV)
|
||||
return_0;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(layer_lv->vg->cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(layer_lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
/* FIXME Incomplete message? Needs more context */
|
||||
@@ -6778,7 +6836,7 @@ static struct logical_volume *_create_virtual_origin(struct cmd_context *cmd,
|
||||
char vorigin_name[NAME_LEN];
|
||||
struct logical_volume *lv;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "zero"))) {
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_ZERO))) {
|
||||
log_error("Zero segment type for virtual origin not found");
|
||||
return NULL;
|
||||
}
|
||||
@@ -6932,7 +6990,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
const char *new_lv_name)
|
||||
{
|
||||
struct cmd_context *cmd = vg->cmd;
|
||||
uint32_t size_rest, size;
|
||||
uint32_t size;
|
||||
uint64_t status = lp->permission | VISIBLE_LV;
|
||||
const struct segment_type *create_segtype = lp->segtype;
|
||||
struct logical_volume *lv, *origin_lv = NULL;
|
||||
@@ -6997,12 +7055,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
lp->stripe_size = vg->extent_size;
|
||||
}
|
||||
|
||||
if ((size_rest = lp->extents % lp->stripes)) {
|
||||
log_print_unless_silent("Rounding size (%d extents) up to stripe boundary "
|
||||
"size (%d extents).", lp->extents,
|
||||
lp->extents - size_rest + lp->stripes);
|
||||
lp->extents = lp->extents - size_rest + lp->stripes;
|
||||
}
|
||||
lp->extents = _round_to_stripe_boundary(vg, lp->extents, lp->stripes, 1);
|
||||
|
||||
if (!lp->extents && !seg_is_thin_volume(lp)) {
|
||||
log_error(INTERNAL_ERROR "Unable to create new logical volume with no extents.");
|
||||
@@ -7060,12 +7113,25 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
}
|
||||
}
|
||||
|
||||
if (seg_is_thin_volume(lp) &&
|
||||
lv_is_new_thin_pool(pool_lv)) {
|
||||
if (seg_is_thin_volume(lp)) {
|
||||
thin_pool_was_active = lv_is_active(pool_lv);
|
||||
if (!check_new_thin_pool(pool_lv))
|
||||
return_NULL;
|
||||
/* New pool is now inactive */
|
||||
if (lv_is_new_thin_pool(pool_lv)) {
|
||||
if (!check_new_thin_pool(pool_lv))
|
||||
return_NULL;
|
||||
/* New pool is now inactive */
|
||||
} else {
|
||||
if (!activate_lv_excl_local(cmd, pool_lv)) {
|
||||
log_error("Aborting. Failed to locally activate thin pool %s.",
|
||||
display_lvname(pool_lv));
|
||||
return 0;
|
||||
}
|
||||
if (!pool_below_threshold(first_seg(pool_lv))) {
|
||||
log_error("Cannot create new thin volume, free space in "
|
||||
"thin pool %s reached threshold.",
|
||||
display_lvname(pool_lv));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (seg_is_cache(lp) &&
|
||||
@@ -7113,7 +7179,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
}
|
||||
/* Create cache origin for cache pool */
|
||||
/* FIXME Eventually support raid/mirrors with -m */
|
||||
if (!(create_segtype = get_segtype_from_string(vg->cmd, "striped")))
|
||||
if (!(create_segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
} else if (seg_is_mirrored(lp) || seg_is_raid(lp)) {
|
||||
if (is_change_activating(lp->activate) && (lp->activate != CHANGE_AEY) &&
|
||||
@@ -7182,8 +7248,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
return NULL;
|
||||
}
|
||||
if (lv_is_cow(origin_lv)) {
|
||||
log_error("Snapshots of snapshots are not "
|
||||
"supported yet.");
|
||||
log_error("Snapshots of snapshots are not supported.");
|
||||
return NULL;
|
||||
}
|
||||
if (lv_is_locked(origin_lv)) {
|
||||
@@ -7229,7 +7294,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
return_NULL;
|
||||
|
||||
/* The snapshot segment gets created later */
|
||||
if (!(create_segtype = get_segtype_from_string(cmd, "striped")))
|
||||
if (!(create_segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_NULL;
|
||||
|
||||
/* Must zero cow */
|
||||
@@ -7323,8 +7388,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
first_seg(lv)->chunk_size = lp->chunk_size;
|
||||
first_seg(lv)->zero_new_blocks = lp->zero ? 1 : 0;
|
||||
first_seg(lv)->discards = lp->discards;
|
||||
/* FIXME: use lowwatermark via lvm.conf global for all thinpools ? */
|
||||
first_seg(lv)->low_water_mark = 0;
|
||||
if (!recalculate_pool_chunk_size_with_dev_hints(lv, lp->passed_args,
|
||||
lp->thin_chunk_size_calc_policy)) {
|
||||
stack;
|
||||
@@ -7626,7 +7689,7 @@ struct logical_volume *lv_create_single(struct volume_group *vg,
|
||||
if (lp->create_pool && !seg_is_pool(lp)) {
|
||||
segtype = lp->segtype;
|
||||
if (seg_is_thin_volume(lp)) {
|
||||
if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin-pool")))
|
||||
if (!(lp->segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_THIN_POOL)))
|
||||
return_NULL;
|
||||
|
||||
if (!(lv = _lv_create_an_lv(vg, lp, lp->pool_name)))
|
||||
@@ -7638,7 +7701,7 @@ struct logical_volume *lv_create_single(struct volume_group *vg,
|
||||
return NULL;
|
||||
}
|
||||
/* origin_name is defined -> creates cache LV with new cache pool */
|
||||
if (!(lp->segtype = get_segtype_from_string(vg->cmd, "cache-pool")))
|
||||
if (!(lp->segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_CACHE_POOL)))
|
||||
return_NULL;
|
||||
|
||||
if (!(lv = _lv_create_an_lv(vg, lp, lp->pool_name)))
|
||||
|
||||
@@ -163,10 +163,9 @@
|
||||
/* vg_read and vg_read_for_update flags */
|
||||
#define READ_ALLOW_INCONSISTENT 0x00010000U
|
||||
#define READ_ALLOW_EXPORTED 0x00020000U
|
||||
#define READ_OK_NOTFOUND 0x00040000U
|
||||
#define READ_WARN_INCONSISTENT 0x00080000U
|
||||
|
||||
/* A meta-flag, useful with toollib for_each_* functions. */
|
||||
#define READ_FOR_UPDATE 0x00100000U
|
||||
#define READ_FOR_UPDATE 0x00100000U /* A meta-flag, useful with toollib for_each_* functions. */
|
||||
|
||||
/* vg's "read_status" field */
|
||||
#define FAILED_INCONSISTENT 0x00000001U
|
||||
@@ -455,7 +454,6 @@ struct lv_segment {
|
||||
struct lv_segment_area *meta_areas; /* For RAID */
|
||||
struct logical_volume *metadata_lv; /* For thin_pool */
|
||||
uint64_t transaction_id; /* For thin_pool, thin */
|
||||
uint64_t low_water_mark; /* For thin_pool */
|
||||
unsigned zero_new_blocks; /* For thin_pool */
|
||||
thin_discards_t discards; /* For thin_pool */
|
||||
struct dm_list thin_messages; /* For thin_pool */
|
||||
@@ -650,9 +648,9 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
* Return a handle to VG metadata.
|
||||
*/
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t flags, uint32_t lockd_state);
|
||||
const char *vgid, uint32_t read_flags, uint32_t lockd_state);
|
||||
struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t flags, uint32_t lockd_state);
|
||||
const char *vgid, uint32_t read_flags, uint32_t lockd_state);
|
||||
|
||||
/*
|
||||
* Test validity of a VG handle.
|
||||
|
||||
@@ -4925,7 +4925,7 @@ static int _vg_access_permitted(struct cmd_context *cmd, struct volume_group *vg
|
||||
* Consolidated locking, reading, and status flag checking.
|
||||
*
|
||||
* If the metadata is inconsistent, setting READ_ALLOW_INCONSISTENT in
|
||||
* misc_flags will return it with FAILED_INCONSISTENT set instead of
|
||||
* read_flags will return it with FAILED_INCONSISTENT set instead of
|
||||
* giving you nothing.
|
||||
*
|
||||
* Use vg_read_error(vg) to determine the result. Nonzero means there were
|
||||
@@ -4933,8 +4933,10 @@ static int _vg_access_permitted(struct cmd_context *cmd, struct volume_group *vg
|
||||
* Zero value means that the VG is open and appropriate locks are held.
|
||||
*/
|
||||
static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t lock_flags,
|
||||
uint64_t status_flags, uint32_t misc_flags,
|
||||
const char *vgid,
|
||||
uint32_t lock_flags,
|
||||
uint64_t status_flags,
|
||||
uint32_t read_flags,
|
||||
uint32_t lockd_state)
|
||||
{
|
||||
struct volume_group *vg = NULL;
|
||||
@@ -4944,7 +4946,7 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
|
||||
uint32_t warn_flags = 0;
|
||||
int already_locked;
|
||||
|
||||
if (misc_flags & READ_ALLOW_INCONSISTENT || lock_flags != LCK_VG_WRITE)
|
||||
if ((read_flags & READ_ALLOW_INCONSISTENT) || (lock_flags != LCK_VG_WRITE))
|
||||
consistent = 0;
|
||||
|
||||
if (!validate_name(vg_name) && !is_orphan_vg(vg_name)) {
|
||||
@@ -4967,7 +4969,7 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
|
||||
consistent_in = consistent;
|
||||
|
||||
warn_flags = WARN_PV_READ;
|
||||
if (consistent || (misc_flags & READ_WARN_INCONSISTENT))
|
||||
if (consistent || (read_flags & READ_WARN_INCONSISTENT))
|
||||
warn_flags |= WARN_INCONSISTENT;
|
||||
|
||||
/* If consistent == 1, we get NULL here if correction fails. */
|
||||
@@ -4976,7 +4978,8 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
|
||||
failure |= FAILED_INCONSISTENT;
|
||||
goto bad;
|
||||
}
|
||||
log_error("Volume group \"%s\" not found", vg_name);
|
||||
if (!(read_flags & READ_OK_NOTFOUND))
|
||||
log_error("Volume group \"%s\" not found", vg_name);
|
||||
failure |= FAILED_NOTFOUND;
|
||||
goto bad;
|
||||
}
|
||||
@@ -5057,20 +5060,20 @@ bad_no_unlock:
|
||||
* *consistent = 1.
|
||||
*/
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t flags, uint32_t lockd_state)
|
||||
const char *vgid, uint32_t read_flags, uint32_t lockd_state)
|
||||
{
|
||||
uint64_t status = UINT64_C(0);
|
||||
uint64_t status_flags = UINT64_C(0);
|
||||
uint32_t lock_flags = LCK_VG_READ;
|
||||
|
||||
if (flags & READ_FOR_UPDATE) {
|
||||
status |= EXPORTED_VG | LVM_WRITE;
|
||||
if (read_flags & READ_FOR_UPDATE) {
|
||||
status_flags |= EXPORTED_VG | LVM_WRITE;
|
||||
lock_flags = LCK_VG_WRITE;
|
||||
}
|
||||
|
||||
if (flags & READ_ALLOW_EXPORTED)
|
||||
status &= ~EXPORTED_VG;
|
||||
if (read_flags & READ_ALLOW_EXPORTED)
|
||||
status_flags &= ~EXPORTED_VG;
|
||||
|
||||
return _vg_lock_and_read(cmd, vg_name, vgid, lock_flags, status, flags, lockd_state);
|
||||
return _vg_lock_and_read(cmd, vg_name, vgid, lock_flags, status_flags, read_flags, lockd_state);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5079,9 +5082,9 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
||||
* request the new metadata to be written and committed).
|
||||
*/
|
||||
struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *vgid, uint32_t flags, uint32_t lockd_state)
|
||||
const char *vgid, uint32_t read_flags, uint32_t lockd_state)
|
||||
{
|
||||
return vg_read(cmd, vg_name, vgid, flags | READ_FOR_UPDATE, lockd_state);
|
||||
return vg_read(cmd, vg_name, vgid, read_flags | READ_FOR_UPDATE, lockd_state);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -83,7 +83,7 @@ int cluster_mirror_is_available(struct cmd_context *cmd)
|
||||
unsigned attr = 0;
|
||||
const struct segment_type *segtype;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "mirror")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_MIRROR)))
|
||||
return_0;
|
||||
|
||||
if (!segtype->ops->target_present)
|
||||
@@ -112,7 +112,7 @@ uint32_t lv_mirror_count(const struct logical_volume *lv)
|
||||
seg = first_seg(lv);
|
||||
|
||||
/* FIXME: RAID10 only supports 2 copies right now */
|
||||
if (!strcmp(seg->segtype->name, "raid10"))
|
||||
if (seg_is_raid10(seg))
|
||||
return 2;
|
||||
|
||||
if (lv_is_pvmove(lv))
|
||||
@@ -1493,8 +1493,7 @@ static int _create_mimage_lvs(struct alloc_handle *ah,
|
||||
}
|
||||
} else {
|
||||
if (!lv_add_segment(ah, m * stripes, stripes, img_lvs[m],
|
||||
get_segtype_from_string(lv->vg->cmd,
|
||||
"striped"),
|
||||
get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED),
|
||||
stripe_size, 0, 0)) {
|
||||
log_error("Aborting. Failed to add mirror image segment "
|
||||
"to %s. Remove new LV and retry.",
|
||||
@@ -1547,8 +1546,7 @@ int remove_mirrors_from_segments(struct logical_volume *lv,
|
||||
seg->area_count = new_mirrors + 1;
|
||||
|
||||
if (!new_mirrors)
|
||||
seg->segtype = get_segtype_from_string(lv->vg->cmd,
|
||||
"striped");
|
||||
seg->segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -1720,7 +1718,7 @@ int fixup_imported_mirrors(struct volume_group *vg)
|
||||
dm_list_iterate_items(lvl, &vg->lvs) {
|
||||
dm_list_iterate_items(seg, &lvl->lv->segments) {
|
||||
if (seg->segtype !=
|
||||
get_segtype_from_string(vg->cmd, "mirror"))
|
||||
get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_MIRROR))
|
||||
continue;
|
||||
|
||||
if (seg->log_lv && !add_seg_to_segs_using_this_lv(seg->log_lv, seg))
|
||||
@@ -1748,7 +1746,7 @@ static int _add_mirrors_that_preserve_segments(struct logical_volume *lv,
|
||||
if (!(parallel_areas = build_parallel_areas_from_lv(lv, 1, 0)))
|
||||
return_0;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "mirror")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_MIRROR)))
|
||||
return_0;
|
||||
|
||||
adjusted_region_size = adjusted_mirror_region_size(lv->vg->extent_size,
|
||||
@@ -2033,7 +2031,7 @@ int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (!(parallel_areas = build_parallel_areas_from_lv(lv, 0, 0)))
|
||||
return_0;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "mirror")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_MIRROR)))
|
||||
return_0;
|
||||
|
||||
if (activation() && segtype->ops->target_present &&
|
||||
@@ -2106,7 +2104,7 @@ int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (!(parallel_areas = build_parallel_areas_from_lv(lv, 0, 0)))
|
||||
return_0;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "mirror")))
|
||||
if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_MIRROR)))
|
||||
return_0;
|
||||
|
||||
ah = allocate_extents(lv->vg, NULL, segtype,
|
||||
|
||||
@@ -438,7 +438,7 @@ int create_pool(struct logical_volume *pool_lv,
|
||||
}
|
||||
|
||||
/* LV is not yet a pool, so it's extension from lvcreate */
|
||||
if (!(striped = get_segtype_from_string(pool_lv->vg->cmd, "striped")))
|
||||
if (!(striped = get_segtype_from_string(pool_lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
if (activation() && striped->ops->target_present &&
|
||||
@@ -561,7 +561,7 @@ struct logical_volume *alloc_pool_metadata(struct logical_volume *pool_lv,
|
||||
.zero = 1,
|
||||
};
|
||||
|
||||
if (!(lvc.segtype = get_segtype_from_string(pool_lv->vg->cmd, "striped")))
|
||||
if (!(lvc.segtype = get_segtype_from_string(pool_lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
/* FIXME: allocate properly space for metadata_lv */
|
||||
@@ -597,7 +597,7 @@ static struct logical_volume *_alloc_pool_metadata_spare(struct volume_group *vg
|
||||
.zero = 1,
|
||||
};
|
||||
|
||||
if (!(lp.segtype = get_segtype_from_string(vg->cmd, "striped")))
|
||||
if (!(lp.segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
/* FIXME: Maybe using silent mode ? */
|
||||
|
||||
@@ -29,9 +29,9 @@ char *pv_fmt_dup(const struct physical_volume *pv)
|
||||
return dm_pool_strdup(pv->vg->vgmem, pv->fmt->name);
|
||||
}
|
||||
|
||||
char *pv_name_dup(const struct physical_volume *pv)
|
||||
char *pv_name_dup(struct dm_pool *mem, const struct physical_volume *pv)
|
||||
{
|
||||
return dm_pool_strdup(pv->vg->vgmem, dev_name(pv->dev));
|
||||
return dm_pool_strdup(mem ? mem : pv->vg->vgmem, dev_name(pv->dev));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -42,9 +42,9 @@ struct id pv_id(const struct physical_volume *pv)
|
||||
return pv_field(pv, id);
|
||||
}
|
||||
|
||||
char *pv_uuid_dup(const struct physical_volume *pv)
|
||||
char *pv_uuid_dup(struct dm_pool *mem, const struct physical_volume *pv)
|
||||
{
|
||||
return id_format_and_copy(pv->vg->vgmem, &pv->id);
|
||||
return id_format_and_copy(mem ? mem : pv->vg->vgmem, &pv->id);
|
||||
}
|
||||
|
||||
char *pv_tags_dup(const struct physical_volume *pv)
|
||||
|
||||
@@ -68,12 +68,12 @@ struct physical_volume {
|
||||
};
|
||||
|
||||
char *pv_fmt_dup(const struct physical_volume *pv);
|
||||
char *pv_name_dup(const struct physical_volume *pv);
|
||||
char *pv_name_dup(struct dm_pool *mem, const struct physical_volume *pv);
|
||||
struct device *pv_dev(const struct physical_volume *pv);
|
||||
const char *pv_vg_name(const struct physical_volume *pv);
|
||||
char *pv_attr_dup(struct dm_pool *mem, const struct physical_volume *pv);
|
||||
const char *pv_dev_name(const struct physical_volume *pv);
|
||||
char *pv_uuid_dup(const struct physical_volume *pv);
|
||||
char *pv_uuid_dup(struct dm_pool *mem, const struct physical_volume *pv);
|
||||
char *pv_tags_dup(const struct physical_volume *pv);
|
||||
uint64_t pv_size(const struct physical_volume *pv);
|
||||
uint64_t pv_size_field(const struct physical_volume *pv);
|
||||
|
||||
@@ -781,7 +781,7 @@ int pvremove_single(struct cmd_context *cmd, const char *pv_name,
|
||||
goto out;
|
||||
}
|
||||
|
||||
info = lvmcache_info_from_pvid(dev->pvid, 1);
|
||||
info = lvmcache_info_from_pvid(dev->pvid, 0);
|
||||
|
||||
if (!dev_test_excl(dev)) {
|
||||
/* FIXME Detect whether device-mapper is still using the device */
|
||||
|
||||
@@ -408,7 +408,7 @@ static struct logical_volume *_alloc_image_component(struct logical_volume *lv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped")))
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
|
||||
if (!lv_add_segment(ah, first_area, 1, tmp_lv, segtype, 0, status, 0)) {
|
||||
@@ -460,9 +460,12 @@ static int _alloc_image_components(struct logical_volume *lv,
|
||||
* individual devies, we must specify how large the individual device
|
||||
* is along with the number we want ('count').
|
||||
*/
|
||||
extents = (segtype->parity_devs) ?
|
||||
(lv->le_count / (seg->area_count - segtype->parity_devs)) :
|
||||
lv->le_count;
|
||||
if (segtype_is_raid10(segtype))
|
||||
extents = lv->le_count / (seg->area_count / 2); /* we enforce 2 mirrors right now */
|
||||
else
|
||||
extents = (segtype->parity_devs) ?
|
||||
(lv->le_count / (seg->area_count - segtype->parity_devs)) :
|
||||
lv->le_count;
|
||||
|
||||
if (!(ah = allocate_extents(lv->vg, NULL, segtype, 0, count, count,
|
||||
region_size, extents, pvs,
|
||||
@@ -867,7 +870,7 @@ static int _raid_extract_images(struct logical_volume *lv, uint32_t new_count,
|
||||
sizeof(*lvl_array) * extract * 2)))
|
||||
return_0;
|
||||
|
||||
if (!(error_segtype = get_segtype_from_string(lv->vg->cmd, "error")))
|
||||
if (!(error_segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_ERROR)))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
@@ -1102,7 +1105,7 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name,
|
||||
}
|
||||
|
||||
if (!seg_is_mirrored(first_seg(lv)) ||
|
||||
!strcmp(first_seg(lv)->segtype->name, SEG_TYPE_NAME_RAID10)) {
|
||||
seg_is_raid10(first_seg(lv))) {
|
||||
log_error("Unable to split logical volume of segment type, %s",
|
||||
lvseg_name(first_seg(lv)));
|
||||
return 0;
|
||||
@@ -1475,13 +1478,11 @@ int lv_raid_reshape(struct logical_volume *lv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(seg->segtype->name, "mirror") &&
|
||||
(!strcmp(new_segtype->name, SEG_TYPE_NAME_RAID1)))
|
||||
return _convert_mirror_to_raid1(lv, new_segtype);
|
||||
if (seg_is_mirror(seg) && segtype_is_raid1(new_segtype))
|
||||
return _convert_mirror_to_raid1(lv, new_segtype);
|
||||
|
||||
log_error("Converting the segment type for %s/%s from %s to %s"
|
||||
" is not yet supported.", lv->vg->name, lv->name,
|
||||
lvseg_name(seg), new_segtype->name);
|
||||
log_error("Converting the segment type for %s/%s from %s to %s is not yet supported.",
|
||||
lv->vg->name, lv->name, lvseg_name(seg), new_segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1663,7 +1664,7 @@ int lv_raid_replace(struct logical_volume *lv,
|
||||
lvseg_name(raid_seg),
|
||||
lv->vg->name, lv->name);
|
||||
return 0;
|
||||
} else if (!strcmp(raid_seg->segtype->name, SEG_TYPE_NAME_RAID10)) {
|
||||
} else if (seg_is_raid10(raid_seg)) {
|
||||
uint32_t i, rebuilds_per_group = 0;
|
||||
/* FIXME: We only support 2-way mirrors in RAID10 currently */
|
||||
uint32_t copies = 2;
|
||||
@@ -1895,7 +1896,7 @@ static int _partial_raid_lv_is_redundant(const struct logical_volume *lv)
|
||||
uint32_t i, s, rebuilds_per_group = 0;
|
||||
uint32_t failed_components = 0;
|
||||
|
||||
if (!strcmp(raid_seg->segtype->name, SEG_TYPE_NAME_RAID10)) {
|
||||
if (seg_is_raid10(raid_seg)) {
|
||||
/* FIXME: We only support 2-way mirrors in RAID10 currently */
|
||||
copies = 2;
|
||||
for (i = 0; i < raid_seg->area_count * copies; i++) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -28,32 +28,95 @@ struct dm_config_node;
|
||||
struct dev_manager;
|
||||
|
||||
/* Feature flags */
|
||||
#define SEG_CAN_SPLIT 0x00000001U
|
||||
#define SEG_AREAS_STRIPED 0x00000002U
|
||||
#define SEG_AREAS_MIRRORED 0x00000004U
|
||||
#define SEG_SNAPSHOT 0x00000008U
|
||||
#define SEG_FORMAT1_SUPPORT 0x00000010U
|
||||
#define SEG_VIRTUAL 0x00000020U
|
||||
#define SEG_CANNOT_BE_ZEROED 0x00000040U
|
||||
#define SEG_MONITORED 0x00000080U
|
||||
#define SEG_REPLICATOR 0x00000100U
|
||||
#define SEG_REPLICATOR_DEV 0x00000200U
|
||||
#define SEG_RAID 0x00000400U
|
||||
#define SEG_THIN_POOL 0x00000800U
|
||||
#define SEG_THIN_VOLUME 0x00001000U
|
||||
#define SEG_CACHE 0x00002000U
|
||||
#define SEG_CACHE_POOL 0x00004000U
|
||||
#define SEG_MIRROR 0x00008000U
|
||||
#define SEG_ONLY_EXCLUSIVE 0x00010000U /* In cluster only exlusive activation */
|
||||
#define SEG_CAN_ERROR_WHEN_FULL 0x00020000U
|
||||
#define SEG_UNKNOWN 0x80000000U
|
||||
#define SEG_CAN_SPLIT 0x0000000000000001ULL
|
||||
#define SEG_AREAS_STRIPED 0x0000000000000002ULL
|
||||
#define SEG_AREAS_MIRRORED 0x0000000000000004ULL
|
||||
#define SEG_SNAPSHOT 0x0000000000000008ULL
|
||||
#define SEG_FORMAT1_SUPPORT 0x0000000000000010ULL
|
||||
#define SEG_VIRTUAL 0x0000000000000020ULL
|
||||
#define SEG_CANNOT_BE_ZEROED 0x0000000000000040ULL
|
||||
#define SEG_MONITORED 0x0000000000000080ULL
|
||||
#define SEG_REPLICATOR 0x0000000000000100ULL
|
||||
#define SEG_REPLICATOR_DEV 0x0000000000000200ULL
|
||||
#define SEG_RAID 0x0000000000000400ULL
|
||||
#define SEG_THIN_POOL 0x0000000000000800ULL
|
||||
#define SEG_THIN_VOLUME 0x0000000000001000ULL
|
||||
#define SEG_CACHE 0x0000000000002000ULL
|
||||
#define SEG_CACHE_POOL 0x0000000000004000ULL
|
||||
#define SEG_MIRROR 0x0000000000008000ULL
|
||||
#define SEG_ONLY_EXCLUSIVE 0x0000000000010000ULL /* In cluster only exlusive activation */
|
||||
#define SEG_CAN_ERROR_WHEN_FULL 0x0000000000020000ULL
|
||||
|
||||
#define SEG_RAID1 0x0000000000100000ULL
|
||||
#define SEG_RAID10 0x0000000000200000ULL
|
||||
#define SEG_RAID4 0x0000000000400000ULL
|
||||
#define SEG_RAID5_N 0x0000000000800000ULL
|
||||
#define SEG_RAID5_LA 0x0000000001000000ULL
|
||||
#define SEG_RAID5_LS 0x0000000002000000ULL
|
||||
#define SEG_RAID5_RA 0x0000000004000000ULL
|
||||
#define SEG_RAID5_RS 0x0000000008000000ULL
|
||||
#define SEG_RAID5 SEG_RAID5_LS
|
||||
#define SEG_RAID6_NC 0x0000000010000000ULL
|
||||
#define SEG_RAID6_NR 0x0000000020000000ULL
|
||||
#define SEG_RAID6_ZR 0x0000000040000000ULL
|
||||
#define SEG_RAID6_LA_6 0x0000000080000000ULL
|
||||
#define SEG_RAID6_LS_6 0x0000000100000000ULL
|
||||
#define SEG_RAID6_RA_6 0x0000000200000000ULL
|
||||
#define SEG_RAID6_RS_6 0x0000000400000000ULL
|
||||
#define SEG_RAID6_N_6 0x0000000800000000ULL
|
||||
#define SEG_RAID6 SEG_RAID6_ZR
|
||||
|
||||
#define SEG_UNKNOWN 0x8000000000000000ULL
|
||||
|
||||
#define SEG_TYPE_NAME_LINEAR "linear"
|
||||
#define SEG_TYPE_NAME_STRIPED "striped"
|
||||
#define SEG_TYPE_NAME_MIRROR "mirror"
|
||||
#define SEG_TYPE_NAME_SNAPSHOT "snapshot"
|
||||
#define SEG_TYPE_NAME_THIN "thin"
|
||||
#define SEG_TYPE_NAME_THIN_POOL "thin-pool"
|
||||
#define SEG_TYPE_NAME_CACHE "cache"
|
||||
#define SEG_TYPE_NAME_CACHE_POOL "cache-pool"
|
||||
#define SEG_TYPE_NAME_ERROR "error"
|
||||
#define SEG_TYPE_NAME_FREE "free"
|
||||
#define SEG_TYPE_NAME_ZERO "zero"
|
||||
#define SEG_TYPE_NAME_RAID "raid"
|
||||
#define SEG_TYPE_NAME_RAID0 "raid0"
|
||||
#define SEG_TYPE_NAME_RAID1 "raid1"
|
||||
#define SEG_TYPE_NAME_RAID10 "raid10"
|
||||
#define SEG_TYPE_NAME_RAID4 "raid4"
|
||||
#define SEG_TYPE_NAME_RAID5 "raid5"
|
||||
#define SEG_TYPE_NAME_RAID5_LA "raid5_la"
|
||||
#define SEG_TYPE_NAME_RAID5_LS "raid5_ls"
|
||||
#define SEG_TYPE_NAME_RAID5_RA "raid5_ra"
|
||||
#define SEG_TYPE_NAME_RAID5_RS "raid5_rs"
|
||||
#define SEG_TYPE_NAME_RAID6 "raid6"
|
||||
#define SEG_TYPE_NAME_RAID6_NC "raid6_nc"
|
||||
#define SEG_TYPE_NAME_RAID6_NR "raid6_nr"
|
||||
#define SEG_TYPE_NAME_RAID6_ZR "raid6_zr"
|
||||
|
||||
#define segtype_is_linear(segtype) (!strcmp(segtype->name, SEG_TYPE_NAME_LINEAR))
|
||||
#define segtype_is_cache(segtype) ((segtype)->flags & SEG_CACHE ? 1 : 0)
|
||||
#define segtype_is_cache_pool(segtype) ((segtype)->flags & SEG_CACHE_POOL ? 1 : 0)
|
||||
#define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
|
||||
#define segtype_is_mirror(segtype) ((segtype)->flags & SEG_MIRROR ? 1 : 0)
|
||||
#define segtype_is_pool(segtype) ((segtype)->flags & (SEG_CACHE_POOL | SEG_THIN_POOL) ? 1 : 0)
|
||||
#define segtype_is_raid(segtype) ((segtype)->flags & SEG_RAID ? 1 : 0)
|
||||
#define segtype_is_raid1(segtype) ((segtype)->flags & SEG_RAID1 ? 1 : 0)
|
||||
#define segtype_is_raid4(segtype) ((segtype)->flags & SEG_RAID4 ? 1 : 0)
|
||||
#define segtype_is_any_raid5(segtype) ((segtype)->flags & \
|
||||
(SEG_RAID5_LS|SEG_RAID5_LA|SEG_RAID5_RS|SEG_RAID5_RA|SEG_RAID5_N) ? 1 : 0)
|
||||
#define segtype_is_raid5_la(segtype) ((segtype)->flags & SEG_RAID5_LA ? 1 : 0)
|
||||
#define segtype_is_raid5_ra(segtype) ((segtype)->flags & SEG_RAID5_RA ? 1 : 0)
|
||||
#define segtype_is_raid5_ls(segtype) ((segtype)->flags & SEG_RAID5_LS ? 1 : 0)
|
||||
#define segtype_is_raid5_rs(segtype) ((segtype)->flags & SEG_RAID5_RS ? 1 : 0)
|
||||
#define segtype_is_any_raid6(segtype) ((segtype)->flags & \
|
||||
(SEG_RAID6_ZR|SEG_RAID6_NC|SEG_RAID6_NR| \
|
||||
SEG_RAID6_LA_6|SEG_RAID6_LS_6|SEG_RAID6_RA_6|SEG_RAID6_RS_6|SEG_RAID6_N_6) ? 1 : 0)
|
||||
#define segtype_is_raid6_nc(segtype) ((segtype)->flags & SEG_RAID6_NC ? 1 : 0)
|
||||
#define segtype_is_raid6_nr(segtype) ((segtype)->flags & SEG_RAID6_NR ? 1 : 0)
|
||||
#define segtype_is_raid6_zr(segtype) ((segtype)->flags & SEG_RAID6_ZR ? 1 : 0)
|
||||
#define segtype_is_raid10(segtype) ((segtype)->flags & SEG_RAID10 ? 1 : 0)
|
||||
#define segtype_is_snapshot(segtype) ((segtype)->flags & SEG_SNAPSHOT ? 1 : 0)
|
||||
#define segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
|
||||
#define segtype_is_thin(segtype) ((segtype)->flags & (SEG_THIN_POOL|SEG_THIN_VOLUME) ? 1 : 0)
|
||||
#define segtype_is_thin_pool(segtype) ((segtype)->flags & SEG_THIN_POOL ? 1 : 0)
|
||||
@@ -68,9 +131,21 @@ struct dev_manager;
|
||||
#define seg_is_mirrored(seg) segtype_is_mirrored((seg)->segtype)
|
||||
#define seg_is_pool(seg) segtype_is_pool((seg)->segtype)
|
||||
#define seg_is_raid(seg) segtype_is_raid((seg)->segtype)
|
||||
#define seg_is_raid1(seg) segtype_is_raid1((seg)->segtype)
|
||||
#define seg_is_raid4(seg) segtype_is_raid4((seg)->segtype)
|
||||
#define seg_is_any_raid5(seg) segtype_is_any_raid5((seg)->segtype)
|
||||
#define seg_is_raid5_la(seg) segtype_is_raid5_la((seg)->segtype)
|
||||
#define seg_is_raid5_ra(seg) segtype_is_raid5_ra((seg)->segtype)
|
||||
#define seg_is_raid5_ls(seg) segtype_is_raid5_ls((seg)->segtype)
|
||||
#define seg_is_raid5_rs(seg) segtype_is_raid5_rs((seg)->segtype)
|
||||
#define seg_is_any_raid6(seg) segtype_is_any_raid6((seg)->segtype)
|
||||
#define seg_is_raid6_zr(seg) segtype_is_raid6_zr((seg)->segtype)
|
||||
#define seg_is_raid6_nr(seg) segtype_is_raid6_nr((seg)->segtype)
|
||||
#define seg_is_raid6_nc(seg) segtype_is_raid6_nc((seg)->segtype)
|
||||
#define seg_is_raid10(seg) segtype_is_raid10((seg)->segtype)
|
||||
#define seg_is_replicator(seg) ((seg)->segtype->flags & SEG_REPLICATOR ? 1 : 0)
|
||||
#define seg_is_replicator_dev(seg) ((seg)->segtype->flags & SEG_REPLICATOR_DEV ? 1 : 0)
|
||||
#define seg_is_snapshot(seg) ((seg)->segtype->flags & SEG_SNAPSHOT ? 1 : 0)
|
||||
#define seg_is_snapshot(seg) segtype_is_snapshot((seg)->segtype)
|
||||
#define seg_is_striped(seg) segtype_is_striped((seg)->segtype)
|
||||
#define seg_is_thin(seg) segtype_is_thin((seg)->segtype)
|
||||
#define seg_is_thin_pool(seg) segtype_is_thin_pool((seg)->segtype)
|
||||
@@ -86,8 +161,8 @@ struct dev_manager;
|
||||
struct segment_type {
|
||||
struct dm_list list; /* Internal */
|
||||
|
||||
uint32_t flags;
|
||||
uint32_t parity_devs; /* Parity drives required by segtype */
|
||||
uint64_t flags;
|
||||
uint32_t parity_devs; /* Parity drives required by segtype */
|
||||
|
||||
struct segtype_handler *ops;
|
||||
const char *name;
|
||||
@@ -152,24 +227,13 @@ struct segment_type *init_unknown_segtype(struct cmd_context *cmd,
|
||||
const char *name);
|
||||
|
||||
#define RAID_FEATURE_RAID10 (1U << 0) /* version 1.3 */
|
||||
#define RAID_FEATURE_RAID0 (1U << 1) /* version 1.7 */
|
||||
#define RAID_FEATURE_RESHAPING (1U << 2) /* version 1.8 */
|
||||
|
||||
#ifdef RAID_INTERNAL
|
||||
int init_raid_segtypes(struct cmd_context *cmd, struct segtype_library *seglib);
|
||||
#endif
|
||||
|
||||
#define SEG_TYPE_NAME_RAID1 "raid1"
|
||||
#define SEG_TYPE_NAME_RAID10 "raid10"
|
||||
#define SEG_TYPE_NAME_RAID4 "raid4"
|
||||
#define SEG_TYPE_NAME_RAID5 "raid5"
|
||||
#define SEG_TYPE_NAME_RAID5_LA "raid5_la"
|
||||
#define SEG_TYPE_NAME_RAID5_LS "raid5_ls"
|
||||
#define SEG_TYPE_NAME_RAID5_RA "raid5_ra"
|
||||
#define SEG_TYPE_NAME_RAID5_RS "raid5_rs"
|
||||
#define SEG_TYPE_NAME_RAID6 "raid6"
|
||||
#define SEG_TYPE_NAME_RAID6_NC "raid6_nc"
|
||||
#define SEG_TYPE_NAME_RAID6_NR "raid6_nr"
|
||||
#define SEG_TYPE_NAME_RAID6_ZR "raid6_zr"
|
||||
|
||||
#ifdef REPLICATOR_INTERNAL
|
||||
int init_replicator_segtype(struct cmd_context *cmd, struct segtype_library *seglib);
|
||||
#endif
|
||||
|
||||
@@ -44,7 +44,7 @@ static uint64_t _cow_extra_chunks(struct cmd_context *cmd, uint64_t n_chunks)
|
||||
unsigned attrs = 0;
|
||||
|
||||
if (activation() &&
|
||||
(segtype = get_segtype_from_string(cmd, "snapshot")) &&
|
||||
(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_SNAPSHOT)) &&
|
||||
segtype->ops->target_present &&
|
||||
segtype->ops->target_present(cmd, NULL, &attrs) &&
|
||||
(attrs & SNAPSHOT_FEATURE_FIXED_LEAK))
|
||||
|
||||
@@ -216,7 +216,7 @@ int thin_pool_feature_supported(const struct logical_volume *lv, int feature)
|
||||
int pool_below_threshold(const struct lv_segment *pool_seg)
|
||||
{
|
||||
dm_percent_t percent;
|
||||
int threshold = DM_PERCENT_1 *
|
||||
dm_percent_t threshold = DM_PERCENT_1 *
|
||||
find_config_tree_int(pool_seg->lv->vg->cmd, activation_thin_pool_autoextend_threshold_CFG,
|
||||
lv_config_profile(pool_seg->lv));
|
||||
|
||||
@@ -224,15 +224,27 @@ int pool_below_threshold(const struct lv_segment *pool_seg)
|
||||
if (!lv_thin_pool_percent(pool_seg->lv, 0, &percent))
|
||||
return_0;
|
||||
|
||||
if (percent >= threshold)
|
||||
if (percent > threshold) {
|
||||
log_debug("Threshold configured for free data space in "
|
||||
"thin pool %s has been reached (%.2f%% >= %.2f%%).",
|
||||
display_lvname(pool_seg->lv),
|
||||
dm_percent_to_float(percent),
|
||||
dm_percent_to_float(threshold));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Metadata */
|
||||
if (!lv_thin_pool_percent(pool_seg->lv, 1, &percent))
|
||||
return_0;
|
||||
|
||||
if (percent >= threshold)
|
||||
if (percent > threshold) {
|
||||
log_debug("Threshold configured for free metadata space in "
|
||||
"thin pool %s has been reached (%.2f%% > %.2f%%).",
|
||||
display_lvname(pool_seg->lv),
|
||||
dm_percent_to_float(percent),
|
||||
dm_percent_to_float(threshold));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -620,7 +620,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
|
||||
return_NULL;
|
||||
|
||||
segtype->ops = &_mirrored_ops;
|
||||
segtype->name = "mirror";
|
||||
segtype->name = SEG_TYPE_NAME_MIRROR;
|
||||
segtype->flags = SEG_MIRROR | SEG_AREAS_MIRRORED;
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
|
||||
@@ -40,6 +40,8 @@ static int _security_level = SECURITY_LEVEL;
|
||||
static char _cmd_name[30] = "";
|
||||
static int _mirror_in_sync = 0;
|
||||
static int _dmeventd_monitor = DEFAULT_DMEVENTD_MONITOR;
|
||||
/* When set, disables update of _dmeventd_monitor & _ignore_suspended_devices */
|
||||
static int _disable_dmeventd_monitoring = 0;
|
||||
static int _background_polling = DEFAULT_BACKGROUND_POLLING;
|
||||
static int _ignore_suspended_devices = 0;
|
||||
static int _ignore_lvm_mirrors = DEFAULT_IGNORE_LVM_MIRRORS;
|
||||
@@ -123,7 +125,13 @@ void init_mirror_in_sync(int in_sync)
|
||||
|
||||
void init_dmeventd_monitor(int reg)
|
||||
{
|
||||
_dmeventd_monitor = reg;
|
||||
if (!_disable_dmeventd_monitoring)
|
||||
_dmeventd_monitor = reg;
|
||||
}
|
||||
|
||||
void init_disable_dmeventd_monitoring(int reg)
|
||||
{
|
||||
_disable_dmeventd_monitoring = reg;
|
||||
}
|
||||
|
||||
void init_background_polling(int polling)
|
||||
@@ -133,7 +141,8 @@ void init_background_polling(int polling)
|
||||
|
||||
void init_ignore_suspended_devices(int ignore)
|
||||
{
|
||||
_ignore_suspended_devices = ignore;
|
||||
if (!_disable_dmeventd_monitoring)
|
||||
_ignore_suspended_devices = ignore;
|
||||
}
|
||||
|
||||
void init_ignore_lvm_mirrors(int scan)
|
||||
|
||||
@@ -38,6 +38,7 @@ void init_lockingfailed(int level);
|
||||
void init_security_level(int level);
|
||||
void init_mirror_in_sync(int in_sync);
|
||||
void init_dmeventd_monitor(int reg);
|
||||
void init_disable_dmeventd_monitoring(int disable);
|
||||
void init_background_polling(int polling);
|
||||
void init_ignore_suspended_devices(int ignore);
|
||||
void init_ignore_lvm_mirrors(int scan);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "lib.h"
|
||||
#include "lvm-signal.h"
|
||||
#include "memlock.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
@@ -60,6 +61,8 @@ void sigint_allow(void)
|
||||
struct sigaction handler;
|
||||
sigset_t sigs;
|
||||
|
||||
if (memlock_count_daemon())
|
||||
return;
|
||||
/*
|
||||
* Do not overwrite the backed-up handler data -
|
||||
* just increase nesting count.
|
||||
@@ -91,6 +94,9 @@ void sigint_allow(void)
|
||||
|
||||
void sigint_restore(void)
|
||||
{
|
||||
if (memlock_count_daemon())
|
||||
return;
|
||||
|
||||
if (!_handler_installed ||
|
||||
--_handler_installed >= MAX_SIGINTS)
|
||||
return;
|
||||
@@ -112,6 +118,9 @@ void block_signals(uint32_t flags __attribute__((unused)))
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
if (memlock_count_daemon())
|
||||
return;
|
||||
|
||||
if (_signals_blocked)
|
||||
return;
|
||||
|
||||
@@ -130,6 +139,9 @@ void block_signals(uint32_t flags __attribute__((unused)))
|
||||
|
||||
void unblock_signals(void)
|
||||
{
|
||||
if (memlock_count_daemon())
|
||||
return;
|
||||
|
||||
/* Don't unblock signals while any locks are held */
|
||||
if (!_signals_blocked)
|
||||
return;
|
||||
|
||||
@@ -638,3 +638,8 @@ void memlock_unlock(struct cmd_context *cmd)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int memlock_count_daemon(void)
|
||||
{
|
||||
return _memlock_count_daemon;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ void critical_section_dec(struct cmd_context *cmd, const char *reason);
|
||||
int critical_section(void);
|
||||
void memlock_inc_daemon(struct cmd_context *cmd);
|
||||
void memlock_dec_daemon(struct cmd_context *cmd);
|
||||
int memlock_count_daemon(void);
|
||||
void memlock_init(struct cmd_context *cmd);
|
||||
void memlock_reset(void);
|
||||
void memlock_unlock(struct cmd_context *cmd);
|
||||
|
||||
112
lib/raid/raid.c
112
lib/raid/raid.c
@@ -55,7 +55,7 @@ static int _raid_text_import_areas(struct lv_segment *seg,
|
||||
const struct dm_config_value *cv)
|
||||
{
|
||||
unsigned int s;
|
||||
struct logical_volume *lv1;
|
||||
struct logical_volume *lv;
|
||||
const char *seg_name = dm_config_parent_name(sn);
|
||||
|
||||
if (!seg->area_count) {
|
||||
@@ -75,23 +75,23 @@ static int _raid_text_import_areas(struct lv_segment *seg,
|
||||
}
|
||||
|
||||
/* Metadata device comes first */
|
||||
if (!(lv1 = find_lv(seg->lv->vg, cv->v.str))) {
|
||||
if (!(lv = find_lv(seg->lv->vg, cv->v.str))) {
|
||||
log_error("Couldn't find volume '%s' for segment '%s'.",
|
||||
cv->v.str ? : "NULL", seg_name);
|
||||
return 0;
|
||||
}
|
||||
if (!set_lv_segment_area_lv(seg, s, lv1, 0, RAID_META))
|
||||
return_0;
|
||||
if (!set_lv_segment_area_lv(seg, s, lv, 0, RAID_META))
|
||||
return_0;
|
||||
|
||||
/* Data device comes second */
|
||||
cv = cv->next;
|
||||
if (!(lv1 = find_lv(seg->lv->vg, cv->v.str))) {
|
||||
if (!(lv = find_lv(seg->lv->vg, cv->v.str))) {
|
||||
log_error("Couldn't find volume '%s' for segment '%s'.",
|
||||
cv->v.str ? : "NULL", seg_name);
|
||||
return 0;
|
||||
}
|
||||
if (!set_lv_segment_area_lv(seg, s, lv1, 0, RAID_IMAGE))
|
||||
return_0;
|
||||
if (!set_lv_segment_area_lv(seg, s, lv, 0, RAID_IMAGE))
|
||||
return_0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -111,49 +111,28 @@ static int _raid_text_import(struct lv_segment *seg,
|
||||
struct dm_hash_table *pv_hash)
|
||||
{
|
||||
const struct dm_config_value *cv;
|
||||
const struct {
|
||||
const char *name;
|
||||
uint32_t *var;
|
||||
} raid_attr_import[] = {
|
||||
{ "region_size", &seg->region_size },
|
||||
{ "stripe_size", &seg->stripe_size },
|
||||
{ "writebehind", &seg->writebehind },
|
||||
{ "min_recovery_rate", &seg->min_recovery_rate },
|
||||
{ "max_recovery_rate", &seg->max_recovery_rate },
|
||||
}, *aip = raid_attr_import;
|
||||
int i;
|
||||
|
||||
if (dm_config_has_node(sn, "region_size")) {
|
||||
if (!dm_config_get_uint32(sn, "region_size", &seg->region_size)) {
|
||||
log_error("Couldn't read 'region_size' for "
|
||||
"segment %s of logical volume %s.",
|
||||
dm_config_parent_name(sn), seg->lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (dm_config_has_node(sn, "stripe_size")) {
|
||||
if (!dm_config_get_uint32(sn, "stripe_size", &seg->stripe_size)) {
|
||||
log_error("Couldn't read 'stripe_size' for "
|
||||
"segment %s of logical volume %s.",
|
||||
dm_config_parent_name(sn), seg->lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (dm_config_has_node(sn, "writebehind")) {
|
||||
if (!dm_config_get_uint32(sn, "writebehind", &seg->writebehind)) {
|
||||
log_error("Couldn't read 'writebehind' for "
|
||||
"segment %s of logical volume %s.",
|
||||
dm_config_parent_name(sn), seg->lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (dm_config_has_node(sn, "min_recovery_rate")) {
|
||||
if (!dm_config_get_uint32(sn, "min_recovery_rate",
|
||||
&seg->min_recovery_rate)) {
|
||||
log_error("Couldn't read 'min_recovery_rate' for "
|
||||
"segment %s of logical volume %s.",
|
||||
dm_config_parent_name(sn), seg->lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (dm_config_has_node(sn, "max_recovery_rate")) {
|
||||
if (!dm_config_get_uint32(sn, "max_recovery_rate",
|
||||
&seg->max_recovery_rate)) {
|
||||
log_error("Couldn't read 'max_recovery_rate' for "
|
||||
"segment %s of logical volume %s.",
|
||||
dm_config_parent_name(sn), seg->lv->name);
|
||||
return 0;
|
||||
for (i = 0; i < DM_ARRAY_SIZE(raid_attr_import); i++, aip++) {
|
||||
if (dm_config_has_node(sn, aip->name)) {
|
||||
if (!dm_config_get_uint32(sn, aip->name, aip->var)) {
|
||||
log_error("Couldn't read '%s' for segment %s of logical volume %s.",
|
||||
aip->name, dm_config_parent_name(sn), seg->lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!dm_config_get_list(sn, "raids", &cv)) {
|
||||
log_error("Couldn't find RAID array for "
|
||||
"segment %s of logical volume %s.",
|
||||
@@ -162,7 +141,7 @@ static int _raid_text_import(struct lv_segment *seg,
|
||||
}
|
||||
|
||||
if (!_raid_text_import_areas(seg, sn, cv)) {
|
||||
log_error("Failed to import RAID images");
|
||||
log_error("Failed to import RAID component pairs.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -242,7 +221,7 @@ static int _raid_add_target_line(struct dev_manager *dm __attribute__((unused)),
|
||||
/* RAID 4/5/6 */
|
||||
params.mirrors = 1;
|
||||
params.stripes = seg->area_count - seg->segtype->parity_devs;
|
||||
} else if (strcmp(seg->segtype->name, SEG_TYPE_NAME_RAID10)) {
|
||||
} else if (seg_is_raid10(seg)) {
|
||||
/* RAID 10 only supports 2 mirrors now */
|
||||
params.mirrors = 2;
|
||||
params.stripes = seg->area_count / 2;
|
||||
@@ -301,8 +280,8 @@ static int _raid_target_percent(void **target_state,
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (!pos || (sscanf(pos, FMTu64 "/" FMTu64 "%n",
|
||||
&numerator, &denominator, &i) != 2)) {
|
||||
if (!pos || (sscanf(pos, FMTu64 "/" FMTu64 "%n", &numerator, &denominator, &i) != 2) ||
|
||||
!denominator) {
|
||||
log_error("Failed to parse %s status fraction: %s",
|
||||
(seg) ? seg->segtype->name : "segment", params);
|
||||
return 0;
|
||||
@@ -331,6 +310,7 @@ static int _raid_target_present(struct cmd_context *cmd,
|
||||
const char *feature;
|
||||
} _features[] = {
|
||||
{ 1, 3, RAID_FEATURE_RAID10, SEG_TYPE_NAME_RAID10 },
|
||||
{ 1, 7, RAID_FEATURE_RAID0, SEG_TYPE_NAME_RAID0 },
|
||||
};
|
||||
|
||||
static int _raid_checked = 0;
|
||||
@@ -434,25 +414,25 @@ static struct segtype_handler _raid_ops = {
|
||||
static const struct raid_type {
|
||||
const char name[12];
|
||||
unsigned parity;
|
||||
int extra_flags;
|
||||
uint64_t extra_flags;
|
||||
} _raid_types[] = {
|
||||
{ SEG_TYPE_NAME_RAID1, 0, SEG_AREAS_MIRRORED },
|
||||
{ SEG_TYPE_NAME_RAID10, 0, SEG_AREAS_MIRRORED },
|
||||
{ SEG_TYPE_NAME_RAID4, 1 },
|
||||
{ SEG_TYPE_NAME_RAID5, 1 },
|
||||
{ SEG_TYPE_NAME_RAID5_LA, 1 },
|
||||
{ SEG_TYPE_NAME_RAID5_LS, 1 },
|
||||
{ SEG_TYPE_NAME_RAID5_RA, 1 },
|
||||
{ SEG_TYPE_NAME_RAID5_RS, 1 },
|
||||
{ SEG_TYPE_NAME_RAID6, 2 },
|
||||
{ SEG_TYPE_NAME_RAID6_NC, 2 },
|
||||
{ SEG_TYPE_NAME_RAID6_NR, 2 },
|
||||
{ SEG_TYPE_NAME_RAID6_ZR, 2 }
|
||||
{ SEG_TYPE_NAME_RAID1, 0, SEG_RAID1 | SEG_AREAS_MIRRORED },
|
||||
{ SEG_TYPE_NAME_RAID10, 0, SEG_RAID10 | SEG_AREAS_MIRRORED },
|
||||
{ SEG_TYPE_NAME_RAID4, 1, SEG_RAID4 },
|
||||
{ SEG_TYPE_NAME_RAID5, 1, SEG_RAID5 },
|
||||
{ SEG_TYPE_NAME_RAID5_LA, 1, SEG_RAID5_LA },
|
||||
{ SEG_TYPE_NAME_RAID5_LS, 1, SEG_RAID5_LS },
|
||||
{ SEG_TYPE_NAME_RAID5_RA, 1, SEG_RAID5_RA },
|
||||
{ SEG_TYPE_NAME_RAID5_RS, 1, SEG_RAID5_RS },
|
||||
{ SEG_TYPE_NAME_RAID6, 2, SEG_RAID6 },
|
||||
{ SEG_TYPE_NAME_RAID6_NC, 2, SEG_RAID6_NC },
|
||||
{ SEG_TYPE_NAME_RAID6_NR, 2, SEG_RAID6_NR },
|
||||
{ SEG_TYPE_NAME_RAID6_ZR, 2, SEG_RAID6_ZR }
|
||||
};
|
||||
|
||||
static struct segment_type *_init_raid_segtype(struct cmd_context *cmd,
|
||||
const struct raid_type *rt,
|
||||
int monitored)
|
||||
uint64_t monitored)
|
||||
{
|
||||
struct segment_type *segtype = dm_zalloc(sizeof(*segtype));
|
||||
|
||||
@@ -482,7 +462,7 @@ int init_multiple_segtypes(struct cmd_context *cmd, struct segtype_library *segl
|
||||
{
|
||||
struct segment_type *segtype;
|
||||
unsigned i;
|
||||
int monitored = 0;
|
||||
uint64_t monitored = 0;
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
# ifdef DMEVENTD
|
||||
|
||||
@@ -63,6 +63,7 @@ FIELD(LVS, lv, SIZ, "LSize", size, 5, size64, lv_size, "Size of LV in current un
|
||||
FIELD(LVS, lv, SIZ, "MSize", lvid, 6, lvmetadatasize, lv_metadata_size, "For thin and cache pools, the size of the LV that holds the metadata.", 0)
|
||||
FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, seg_count, "Number of segments in LV.", 0)
|
||||
FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, origin, "For snapshots, the origin device of this LV.", 0)
|
||||
FIELD(LVS, lv, STR, "Origin UUID", lvid, 38, originuuid, origin_uuid, "For snapshots, the UUID of origin device of this LV.", 0)
|
||||
FIELD(LVS, lv, SIZ, "OSize", lvid, 5, originsize, origin_size, "For snapshots, the size of the origin device of this LV.", 0)
|
||||
FIELD(LVS, lv, STR_LIST, "Ancestors", lvid, 12, lvancestors, lv_ancestors, "Ancestors of this LV.", 0)
|
||||
FIELD(LVS, lv, STR_LIST, "Descendants", lvid, 12, lvdescendants, lv_descendants, "Descendants of this LV.", 0)
|
||||
@@ -77,11 +78,17 @@ FIELD(LVS, lv, NUM, "WBehind", lvid, 7, raidwritebehind, raid_write_behind, "For
|
||||
FIELD(LVS, lv, NUM, "MinSync", lvid, 7, raidminrecoveryrate, raid_min_recovery_rate, "For RAID1, the minimum recovery I/O load in kiB/sec/disk.", 0)
|
||||
FIELD(LVS, lv, NUM, "MaxSync", lvid, 7, raidmaxrecoveryrate, raid_max_recovery_rate, "For RAID1, the maximum recovery I/O load in kiB/sec/disk.", 0)
|
||||
FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, move_pv, "For pvmove, Source PV of temporary LV created by pvmove.", 0)
|
||||
FIELD(LVS, lv, STR, "Move UUID", lvid, 38, movepvuuid, move_pv_uuid, "For pvmove, the UUID of Source PV of temporary LV created by pvmove.", 0)
|
||||
FIELD(LVS, lv, STR, "Convert", lvid, 7, convertlv, convert_lv, "For lvconvert, Name of temporary LV created by lvconvert.", 0)
|
||||
FIELD(LVS, lv, STR, "Convert", lvid, 38, convertlvuuid, convert_lv_uuid, "For lvconvert, UUID of temporary LV created by lvconvert.", 0)
|
||||
FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, mirror_log, "For mirrors, the LV holding the synchronisation log.", 0)
|
||||
FIELD(LVS, lv, STR, "Log UUID", lvid, 38, loglvuuid, mirror_log_uuid, "For mirrors, the UUID of the LV holding the synchronisation log.", 0)
|
||||
FIELD(LVS, lv, STR, "Data", lvid, 4, datalv, data_lv, "For thin and cache pools, the LV holding the associated data.", 0)
|
||||
FIELD(LVS, lv, STR, "Data UUID", lvid, 38, datalvuuid, data_lv_uuid, "For thin and cache pools, the UUID of the LV holding the associated data.", 0)
|
||||
FIELD(LVS, lv, STR, "Meta", lvid, 4, metadatalv, metadata_lv, "For thin and cache pools, the LV holding the associated metadata.", 0)
|
||||
FIELD(LVS, lv, STR, "Meta UUID", lvid, 38, metadatalvuuid, metadata_lv_uuid, "For thin and cache pools, the UUID of the LV holding the associated metadata.", 0)
|
||||
FIELD(LVS, lv, STR, "Pool", lvid, 4, poollv, pool_lv, "For thin volumes, the thin pool LV for this volume.", 0)
|
||||
FIELD(LVS, lv, STR, "Pool UUID", lvid, 38, poollvuuid, pool_lv_uuid, "For thin volumes, the UUID of the thin pool LV for this volume.", 0)
|
||||
FIELD(LVS, lv, STR_LIST, "LV Tags", tags, 7, tags, lv_tags, "Tags, if any.", 0)
|
||||
FIELD(LVS, lv, STR, "LProfile", lvid, 8, lvprofile, lv_profile, "Configuration profile attached to this LV.", 0)
|
||||
FIELD(LVS, lv, STR, "Lock Args", lvid, 9, lvlockargs, lv_lockargs, "Lock args of the LV used by lvmlockd.", 0)
|
||||
@@ -151,7 +158,8 @@ FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, vg_extent_count, "Total num
|
||||
FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, vg_free_count, "Total number of unallocated Physical Extents.", 0)
|
||||
FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, max_lv, "Maximum number of LVs allowed in VG or 0 if unlimited.", 0)
|
||||
FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, max_pv, "Maximum number of PVs allowed in VG or 0 if unlimited.", 0)
|
||||
FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, pv_count, "Number of PVs.", 0)
|
||||
FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, pv_count, "Number of PVs in VG.", 0)
|
||||
FIELD(VGS, vg, NUM, "#PV Missing", cmd, 11, vgmissingpvcount, vg_missing_pv_count, "Number of PVs in VG which are missing.", 0)
|
||||
FIELD(VGS, vg, NUM, "#LV", cmd, 3, lvcount, lv_count, "Number of LVs.", 0)
|
||||
FIELD(VGS, vg, NUM, "#SN", cmd, 3, snapcount, snap_count, "Number of snapshots.", 0)
|
||||
FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, vg_seqno, "Revision number of internal metadata. Incremented whenever it changes.", 0)
|
||||
@@ -183,7 +191,9 @@ FIELD(SEGS, seg, SIZ, "SSize", list, 5, segsize, seg_size, "Size of segment in c
|
||||
FIELD(SEGS, seg, SIZ, "SSize", list, 5, segsizepe, seg_size_pe, "Size of segment in physical extents.", 0)
|
||||
FIELD(SEGS, seg, STR_LIST, "Seg Tags", tags, 8, tags, seg_tags, "Tags, if any.", 0)
|
||||
FIELD(SEGS, seg, STR, "PE Ranges", list, 9, peranges, seg_pe_ranges, "Ranges of Physical Extents of underlying devices in command line format.", 0)
|
||||
FIELD(SEGS, seg, STR, "Metadata LE Ranges", list, 18, metadataleranges, seg_metadata_le_ranges, "Ranges of Logical Extents of underlying metadata devices in command line format.", 0)
|
||||
FIELD(SEGS, seg, STR, "Devices", list, 7, devices, devices, "Underlying devices used with starting extent numbers.", 0)
|
||||
FIELD(SEGS, seg, STR, "Metadata Devs", list, 13, metadatadevices, metadata_devices, "Underlying metadata devices used with starting extent numbers.", 0)
|
||||
FIELD(SEGS, seg, STR, "Monitor", list, 7, segmonitor, seg_monitor, "Dmeventd monitoring status of the segment.", 0)
|
||||
FIELD(SEGS, seg, STR, "Cache Policy", list, 12, cache_policy, cache_policy, "The cache policy (cached segments only).", 0)
|
||||
FIELD(SEGS, seg, STR_LIST, "Cache Settings", list, 14, cache_settings, cache_settings, "Cache settings/parameters (cached segments only).", 0)
|
||||
|
||||
@@ -149,11 +149,11 @@ static dm_percent_t _metadata_percent(const struct logical_volume *lv)
|
||||
/* PV */
|
||||
GET_PV_STR_PROPERTY_FN(pv_fmt, pv_fmt_dup(pv))
|
||||
#define _pv_fmt_set prop_not_implemented_set
|
||||
GET_PV_STR_PROPERTY_FN(pv_uuid, pv_uuid_dup(pv))
|
||||
GET_PV_STR_PROPERTY_FN(pv_uuid, pv_uuid_dup(pv->vg->vgmem, pv))
|
||||
#define _pv_uuid_set prop_not_implemented_set
|
||||
GET_PV_NUM_PROPERTY_FN(dev_size, SECTOR_SIZE * pv_dev_size(pv))
|
||||
#define _dev_size_set prop_not_implemented_set
|
||||
GET_PV_STR_PROPERTY_FN(pv_name, pv_name_dup(pv))
|
||||
GET_PV_STR_PROPERTY_FN(pv_name, pv_name_dup(pv->vg->vgmem, pv))
|
||||
#define _pv_name_set prop_not_implemented_set
|
||||
GET_PV_NUM_PROPERTY_FN(pv_mda_free, SECTOR_SIZE * pv_mda_free(pv))
|
||||
#define _pv_mda_free_set prop_not_implemented_set
|
||||
@@ -264,7 +264,7 @@ GET_PV_NUM_PROPERTY_FN(pv_ba_size, SECTOR_SIZE * pv->ba_size)
|
||||
#define _cache_write_misses_get prop_not_implemented_get
|
||||
|
||||
/* LV */
|
||||
GET_LV_STR_PROPERTY_FN(lv_uuid, lv_uuid_dup(lv))
|
||||
GET_LV_STR_PROPERTY_FN(lv_uuid, lv_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _lv_uuid_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(lv_name, lv_name_dup(lv->vg->vgmem, lv))
|
||||
#define _lv_name_set prop_not_implemented_set
|
||||
@@ -298,6 +298,8 @@ GET_LV_NUM_PROPERTY_FN(seg_count, dm_list_size(&lv->segments))
|
||||
#define _seg_count_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(origin, lv_origin_dup(lv->vg->vgmem, lv))
|
||||
#define _origin_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(origin_uuid, lv_origin_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _origin_uuid_set prop_not_implemented_set
|
||||
GET_LV_NUM_PROPERTY_FN(origin_size, (SECTOR_SIZE * lv_origin_size(lv)))
|
||||
#define _origin_size_set prop_not_implemented_set
|
||||
#define _lv_ancestors_set prop_not_implemented_set
|
||||
@@ -322,20 +324,32 @@ GET_LV_STR_PROPERTY_FN(raid_sync_action, _raidsyncaction(lv))
|
||||
#define _raid_sync_action_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(move_pv, lv_move_pv_dup(lv->vg->vgmem, lv))
|
||||
#define _move_pv_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(move_pv_uuid, lv_move_pv_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _move_pv_uuid_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(convert_lv, lv_convert_lv_dup(lv->vg->vgmem, lv))
|
||||
#define _convert_lv_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(convert_lv_uuid, lv_convert_lv_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _convert_lv_uuid_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(lv_tags, lv_tags_dup(lv))
|
||||
#define _lv_tags_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(mirror_log, lv_mirror_log_dup(lv->vg->vgmem, lv))
|
||||
#define _mirror_log_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(mirror_log_uuid, lv_mirror_log_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _mirror_log_uuid_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(lv_modules, lv_modules_dup(lv->vg->vgmem, lv))
|
||||
#define _lv_modules_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(data_lv, lv_data_lv_dup(lv->vg->vgmem, lv))
|
||||
#define _data_lv_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(data_lv_uuid, lv_data_lv_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _data_lv_uuid_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(metadata_lv, lv_metadata_lv_dup(lv->vg->vgmem, lv))
|
||||
#define _metadata_lv_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(metadata_lv_uuid, lv_metadata_lv_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _metadata_lv_uuid_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(pool_lv, lv_pool_lv_dup(lv->vg->vgmem, lv))
|
||||
#define _pool_lv_set prop_not_implemented_set
|
||||
GET_LV_STR_PROPERTY_FN(pool_lv_uuid, lv_pool_lv_uuid_dup(lv->vg->vgmem, lv))
|
||||
#define _pool_lv_uuid_set prop_not_implemented_set
|
||||
GET_LV_NUM_PROPERTY_FN(data_percent, _data_percent(lv))
|
||||
#define _data_percent_set prop_not_implemented_set
|
||||
GET_LV_NUM_PROPERTY_FN(metadata_percent, _metadata_percent(lv))
|
||||
@@ -406,6 +420,8 @@ GET_VG_NUM_PROPERTY_FN(vg_mda_copies, (vg_mda_copies(vg)))
|
||||
SET_VG_NUM_PROPERTY_FN(vg_mda_copies, vg_set_mda_copies)
|
||||
GET_VG_STR_PROPERTY_FN(vg_profile, vg_profile_dup(vg))
|
||||
#define _vg_profile_set prop_not_implemented_set
|
||||
GET_VG_NUM_PROPERTY_FN(vg_missing_pv_count, vg_missing_pv_count(vg))
|
||||
#define _vg_missing_pv_count_set prop_not_implemented_set
|
||||
|
||||
/* LVSEG */
|
||||
GET_LVSEG_STR_PROPERTY_FN(segtype, lvseg_segtype_dup(lvseg->lv->vg->vgmem, lvseg))
|
||||
@@ -449,8 +465,13 @@ GET_LVSEG_STR_PROPERTY_FN(seg_tags, lvseg_tags_dup(lvseg))
|
||||
GET_LVSEG_STR_PROPERTY_FN(seg_pe_ranges,
|
||||
lvseg_seg_pe_ranges(lvseg->lv->vg->vgmem, lvseg))
|
||||
#define _seg_pe_ranges_set prop_not_implemented_set
|
||||
GET_LVSEG_STR_PROPERTY_FN(seg_metadata_le_ranges,
|
||||
lvseg_seg_metadata_le_ranges(lvseg->lv->vg->vgmem, lvseg))
|
||||
#define _seg_metadata_le_ranges_set prop_not_implemented_set
|
||||
GET_LVSEG_STR_PROPERTY_FN(devices, lvseg_devices(lvseg->lv->vg->vgmem, lvseg))
|
||||
#define _devices_set prop_not_implemented_set
|
||||
GET_LVSEG_STR_PROPERTY_FN(metadata_devices, lvseg_metadata_devices(lvseg->lv->vg->vgmem, lvseg))
|
||||
#define _metadata_devices_set prop_not_implemented_set
|
||||
GET_LVSEG_STR_PROPERTY_FN(seg_monitor, lvseg_monitor_dup(lvseg->lv->vg->vgmem, lvseg))
|
||||
#define _seg_monitor_set prop_not_implemented_set
|
||||
|
||||
|
||||
@@ -1271,6 +1271,18 @@ static int _chars_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((
|
||||
return dm_report_field_string(rh, field, (const char * const *) &data);
|
||||
}
|
||||
|
||||
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)))
|
||||
return_0;
|
||||
|
||||
return _field_set_value(field, repstr, NULL);
|
||||
}
|
||||
|
||||
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)))
|
||||
@@ -1292,6 +1304,18 @@ static int _devices_disp(struct dm_report *rh __attribute__((unused)), struct dm
|
||||
return _field_set_value(field, str, NULL);
|
||||
}
|
||||
|
||||
static int _metadatadevices_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_metadata_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)))
|
||||
@@ -1304,6 +1328,18 @@ static int _peranges_disp(struct dm_report *rh __attribute__((unused)), struct d
|
||||
return _field_set_value(field, str, NULL);
|
||||
}
|
||||
|
||||
static int _metadataleranges_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_metadata_le_ranges(mem, (const struct lv_segment *) data)))
|
||||
return_0;
|
||||
|
||||
return _field_set_value(field, str, NULL);
|
||||
}
|
||||
|
||||
static int _tags_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private)
|
||||
@@ -1543,17 +1579,37 @@ static int _segtype_disp(struct dm_report *rh __attribute__((unused)),
|
||||
return _field_set_value(field, name, NULL);
|
||||
}
|
||||
|
||||
static int _do_loglv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)),
|
||||
int uuid)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const char *repstr = NULL;
|
||||
|
||||
if (uuid)
|
||||
repstr = lv_mirror_log_uuid_dup(mem, lv);
|
||||
else
|
||||
repstr = lv_mirror_log_dup(mem, lv);
|
||||
|
||||
if (repstr)
|
||||
return dm_report_field_string(rh, field, &repstr);
|
||||
|
||||
return _field_set_value(field, "", 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)))
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const char *name;
|
||||
return _do_loglv_disp(rh, mem, field, data, private, 0);
|
||||
}
|
||||
|
||||
if ((name = lv_mirror_log_dup(mem, lv)))
|
||||
return dm_report_field_string(rh, field, &name);
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
static int _loglvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
return _do_loglv_disp(rh, mem, field, data, private, 1);
|
||||
}
|
||||
|
||||
static int _lvname_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
@@ -1612,15 +1668,52 @@ static int _lvparent_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
return _field_set_value(field, repstr, NULL);
|
||||
}
|
||||
|
||||
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)))
|
||||
static int _do_datalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)),
|
||||
int uuid)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const struct lv_segment *seg = (lv_is_pool(lv)) ? first_seg(lv) : NULL;
|
||||
|
||||
if (seg)
|
||||
return _lvname_disp(rh, mem, field, seg_lv(seg, 0), private);
|
||||
if (seg) {
|
||||
if (uuid)
|
||||
return _uuid_disp(rh, mem, field, &seg_lv(seg, 0)->lvid.id[1], private);
|
||||
else
|
||||
return _lvname_disp(rh, mem, field, seg_lv(seg, 0), private);
|
||||
}
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
}
|
||||
|
||||
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)))
|
||||
{
|
||||
return _do_datalv_disp(rh, mem, field, data, private, 0);
|
||||
}
|
||||
|
||||
static int _datalvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
return _do_datalv_disp(rh, mem, field, data, private, 1);
|
||||
}
|
||||
|
||||
static int _do_metadatalv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)),
|
||||
int uuid)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const struct lv_segment *seg = (lv_is_pool(lv)) ? first_seg(lv) : NULL;
|
||||
|
||||
if (seg) {
|
||||
if (uuid)
|
||||
return _uuid_disp(rh, mem, field, &seg->metadata_lv->lvid.id[1], private);
|
||||
else
|
||||
return _lvname_disp(rh, mem, field, seg->metadata_lv, private);
|
||||
}
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
}
|
||||
@@ -1629,11 +1722,31 @@ static int _metadatalv_disp(struct dm_report *rh, struct dm_pool *mem __attribut
|
||||
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_pool(lv)) ? first_seg(lv) : NULL;
|
||||
return _do_metadatalv_disp(rh, mem, field, data, private, 0);
|
||||
}
|
||||
|
||||
if (seg)
|
||||
return _lvname_disp(rh, mem, field, seg->metadata_lv, private);
|
||||
static int _metadatalvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
return _do_metadatalv_disp(rh, mem, field, data, private, 1);
|
||||
}
|
||||
|
||||
static int _do_poollv_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private,
|
||||
int uuid)
|
||||
{
|
||||
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) {
|
||||
if (uuid)
|
||||
return _uuid_disp(rh, mem, field, &seg->pool_lv->lvid.id[1], private);
|
||||
else
|
||||
return _lvname_disp(rh, mem, field, seg->pool_lv, private);
|
||||
}
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
}
|
||||
@@ -1642,14 +1755,14 @@ static int _poollv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__(
|
||||
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;
|
||||
return _do_poollv_disp(rh, mem, field, data, private, 0);
|
||||
}
|
||||
|
||||
if (seg)
|
||||
return _lvname_disp(rh, mem, field, seg->pool_lv, private);
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
static int _poollvuuid_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
return _do_poollv_disp(rh, mem, field, data, private, 1);
|
||||
}
|
||||
|
||||
static int _lvpath_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
@@ -1678,26 +1791,44 @@ static int _lvdmpath_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
return _field_set_value(field, repstr, NULL);
|
||||
}
|
||||
|
||||
static int _do_origin_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private,
|
||||
int uuid)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const struct lv_segment *seg = first_seg(lv);
|
||||
struct logical_volume *origin;
|
||||
|
||||
if (lv_is_cow(lv))
|
||||
origin = origin_from_cow(lv);
|
||||
else if (lv_is_cache(lv) && !lv_is_pending_delete(lv))
|
||||
origin = seg_lv(seg, 0);
|
||||
else if (lv_is_thin_volume(lv) && first_seg(lv)->origin)
|
||||
origin = first_seg(lv)->origin;
|
||||
else if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv)
|
||||
origin = first_seg(lv)->external_lv;
|
||||
else
|
||||
return _field_set_value(field, "", NULL);
|
||||
|
||||
if (uuid)
|
||||
return _uuid_disp(rh, mem, field, &origin->lvid.id[1], private);
|
||||
else
|
||||
return _lvname_disp(rh, mem, field, origin, private);
|
||||
}
|
||||
|
||||
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);
|
||||
return _do_origin_disp(rh, mem, field, data, private, 0);
|
||||
}
|
||||
|
||||
if (lv_is_cow(lv))
|
||||
return _lvname_disp(rh, mem, field, origin_from_cow(lv), private);
|
||||
|
||||
if (lv_is_cache(lv) && !lv_is_pending_delete(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 _originuuid_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private)
|
||||
{
|
||||
return _do_origin_disp(rh, mem, field, data, private, 1);
|
||||
}
|
||||
|
||||
static int _find_ancestors(struct _str_list_append_baton *ancestors,
|
||||
@@ -1800,15 +1931,54 @@ static int _lvdescendants_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
return _field_set_string_list(rh, field, descendants.result, private, 0);
|
||||
}
|
||||
|
||||
static int _do_movepv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)),
|
||||
int uuid)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const char *repstr;
|
||||
|
||||
if (uuid)
|
||||
repstr = lv_move_pv_uuid_dup(mem, lv);
|
||||
else
|
||||
repstr = lv_move_pv_dup(mem, lv);
|
||||
|
||||
if (repstr)
|
||||
return dm_report_field_string(rh, field, &repstr);
|
||||
|
||||
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)))
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const char *name;
|
||||
return _do_movepv_disp(rh, mem, field, data, private, 0);
|
||||
}
|
||||
|
||||
if ((name = lv_move_pv_dup(mem, lv)))
|
||||
return dm_report_field_string(rh, field, &name);
|
||||
static int _movepvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
return _do_movepv_disp(rh, mem, field, data, private, 1);
|
||||
}
|
||||
|
||||
static int _do_convertlv_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)),
|
||||
int uuid)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const char *repstr;
|
||||
|
||||
if (uuid)
|
||||
repstr = lv_convert_lv_uuid_dup(mem, lv);
|
||||
else
|
||||
repstr = lv_convert_lv_dup(mem, lv);
|
||||
|
||||
if (repstr)
|
||||
return dm_report_field_string(rh, field, &repstr);
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
}
|
||||
@@ -1817,13 +1987,14 @@ static int _convertlv_disp(struct dm_report *rh, struct dm_pool *mem __attribute
|
||||
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;
|
||||
return _do_convertlv_disp(rh, mem, field, data, private, 0);
|
||||
}
|
||||
|
||||
if ((name = lv_convert_lv_dup(mem, lv)))
|
||||
return dm_report_field_string(rh, field, &name);
|
||||
|
||||
return _field_set_value(field, "", NULL);
|
||||
static int _convertlvuuid_disp(struct dm_report *rh, struct dm_pool *mem __attribute__((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute__((unused)))
|
||||
{
|
||||
return _do_convertlv_disp(rh, mem, field, data, private, 1);
|
||||
}
|
||||
|
||||
static int _size32_disp(struct dm_report *rh __attribute__((unused)), struct dm_pool *mem,
|
||||
@@ -2187,30 +2358,16 @@ static int _vglockargs_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
return _string_disp(rh, mem, field, &repstr, 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)))
|
||||
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;
|
||||
if (!label->dev)
|
||||
return _field_set_value(field, "", NULL);
|
||||
|
||||
return _field_set_value(field, repstr, NULL);
|
||||
return _uuid_disp(rh, mem, field, label->dev->pvid, private);
|
||||
}
|
||||
|
||||
static int _pvmdas_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
@@ -2281,6 +2438,17 @@ static int _vgprofile_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
return _field_set_value(field, "", NULL);
|
||||
}
|
||||
|
||||
static int _vgmissingpvcount_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_missing_pv_count(vg);
|
||||
|
||||
return _uint32_disp(rh, mem, field, &count, private);
|
||||
}
|
||||
|
||||
|
||||
static int _pvmdafree_disp(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private)
|
||||
@@ -3228,6 +3396,21 @@ void *report_init_for_selection(struct cmd_context *cmd,
|
||||
cmd);
|
||||
}
|
||||
|
||||
const char *report_get_field_prefix(report_type_t report_type_id)
|
||||
{
|
||||
const struct dm_report_object_type *report_types, *report_type;
|
||||
|
||||
report_types = report_type_id & DEVTYPES ? _devtypes_report_types
|
||||
: _report_types;
|
||||
|
||||
for (report_type = report_types; report_type->id; report_type++) {
|
||||
if (report_type_id & report_type->id)
|
||||
return report_type->prefix;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a row of data for an object
|
||||
*/
|
||||
|
||||
@@ -71,6 +71,7 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
|
||||
int quoted, int columns_as_rows, const char *selection);
|
||||
void *report_init_for_selection(struct cmd_context *cmd, report_type_t *report_type,
|
||||
const char *selection);
|
||||
const char *report_get_field_prefix(report_type_t report_type);
|
||||
int report_for_selection(struct cmd_context *cmd,
|
||||
struct selection_handle *sh,
|
||||
struct physical_volume *pv,
|
||||
|
||||
@@ -259,7 +259,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
|
||||
return_NULL;
|
||||
|
||||
segtype->ops = &_snapshot_ops;
|
||||
segtype->name = "snapshot";
|
||||
segtype->name = SEG_TYPE_NAME_SNAPSHOT;
|
||||
segtype->flags = SEG_SNAPSHOT | SEG_CANNOT_BE_ZEROED | SEG_ONLY_EXCLUSIVE;
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
static const char *_striped_name(const struct lv_segment *seg)
|
||||
{
|
||||
return (seg->area_count == 1) ? "linear" : seg->segtype->name;
|
||||
return (seg->area_count == 1) ? SEG_TYPE_NAME_LINEAR : seg->segtype->name;
|
||||
}
|
||||
|
||||
static void _striped_display(const struct lv_segment *seg)
|
||||
@@ -229,7 +229,7 @@ struct segment_type *init_striped_segtype(struct cmd_context *cmd)
|
||||
return_NULL;
|
||||
|
||||
segtype->ops = &_striped_ops;
|
||||
segtype->name = "striped";
|
||||
segtype->name = SEG_TYPE_NAME_STRIPED;
|
||||
segtype->flags =
|
||||
SEG_CAN_SPLIT | SEG_AREAS_STRIPED | SEG_FORMAT1_SUPPORT;
|
||||
|
||||
|
||||
@@ -118,10 +118,6 @@ static int _thin_pool_text_import(struct lv_segment *seg,
|
||||
else if (!set_pool_discards(&seg->discards, discards_str))
|
||||
return SEG_LOG_ERROR("Discards option unsupported for");
|
||||
|
||||
if (dm_config_has_node(sn, "low_water_mark") &&
|
||||
!dm_config_get_uint64(sn, "low_water_mark", &seg->low_water_mark))
|
||||
return SEG_LOG_ERROR("Could not read low_water_mark");
|
||||
|
||||
if ((seg->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE) ||
|
||||
(seg->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE))
|
||||
return SEG_LOG_ERROR("Unsupported value %u for chunk_size",
|
||||
@@ -169,9 +165,6 @@ static int _thin_pool_text_export(const struct lv_segment *seg, struct formatter
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seg->low_water_mark)
|
||||
outf(f, "low_water_mark = %" PRIu64, seg->low_water_mark);
|
||||
|
||||
if (seg->zero_new_blocks)
|
||||
outf(f, "zero_new_blocks = 1");
|
||||
|
||||
@@ -266,6 +259,8 @@ static int _thin_pool_add_target_line(struct dev_manager *dm,
|
||||
struct lvinfo info;
|
||||
uint64_t transaction_id = 0;
|
||||
unsigned attr;
|
||||
uint64_t low_water_mark;
|
||||
int threshold;
|
||||
|
||||
if (!_thin_target_present(cmd, NULL, &attr))
|
||||
return_0;
|
||||
@@ -277,27 +272,37 @@ static int _thin_pool_add_target_line(struct dev_manager *dm,
|
||||
|
||||
if (!(attr & THIN_FEATURE_BLOCK_SIZE) &&
|
||||
(seg->chunk_size & (seg->chunk_size - 1))) {
|
||||
log_error("Thin pool target does not support %uKiB chunk size "
|
||||
"(needs kernel >= 3.6).", seg->chunk_size / 2);
|
||||
log_error("Thin pool target does not support %s chunk size (needs"
|
||||
" kernel >= 3.6).", display_size(cmd, seg->chunk_size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(metadata_dlid = build_dm_uuid(mem, seg->metadata_lv, NULL))) {
|
||||
log_error("Failed to build uuid for metadata LV %s.",
|
||||
seg->metadata_lv->name);
|
||||
display_lvname(seg->metadata_lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pool_dlid = build_dm_uuid(mem, seg_lv(seg, 0), NULL))) {
|
||||
log_error("Failed to build uuid for pool LV %s.",
|
||||
seg_lv(seg, 0)->name);
|
||||
display_lvname(seg_lv(seg, 0)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
threshold = find_config_tree_int(seg->lv->vg->cmd,
|
||||
activation_thin_pool_autoextend_threshold_CFG,
|
||||
lv_config_profile(seg->lv));
|
||||
if (threshold < 50)
|
||||
threshold = 50;
|
||||
if (threshold < 100)
|
||||
low_water_mark = (len * threshold + 99) / 100;
|
||||
else
|
||||
low_water_mark = len;
|
||||
|
||||
if (!dm_tree_node_add_thin_pool_target(node, len,
|
||||
seg->transaction_id,
|
||||
metadata_dlid, pool_dlid,
|
||||
seg->chunk_size, seg->low_water_mark,
|
||||
seg->chunk_size, low_water_mark,
|
||||
seg->zero_new_blocks ? 0 : 1))
|
||||
return_0;
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ int id_valid(struct id *id)
|
||||
|
||||
for (i = 0; i < ID_LEN; i++)
|
||||
if (!_inverse_c[id->uuid[i]]) {
|
||||
log_error("UUID contains invalid character");
|
||||
log_error("UUID contains invalid character '%c'", id->uuid[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ struct segment_type *init_zero_segtype(struct cmd_context *cmd)
|
||||
return_NULL;
|
||||
|
||||
segtype->ops = &_zero_ops;
|
||||
segtype->name = "zero";
|
||||
segtype->name = SEG_TYPE_NAME_ZERO;
|
||||
segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL | SEG_CANNOT_BE_ZEROED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
@@ -289,7 +289,7 @@ static int close_enough(double d1, double d2)
|
||||
return fabs(d1 - d2) < DBL_EPSILON;
|
||||
}
|
||||
|
||||
static int compare_value(struct dm_config_value *a, struct dm_config_value *b)
|
||||
int compare_value(struct dm_config_value *a, struct dm_config_value *b)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ struct dm_config_node *make_config_node(struct dm_config_tree *cft,
|
||||
struct dm_config_node *parent,
|
||||
struct dm_config_node *pre_sib);
|
||||
|
||||
int compare_value(struct dm_config_value *a, struct dm_config_value *b);
|
||||
int compare_config(struct dm_config_node *a, struct dm_config_node *b);
|
||||
|
||||
struct dm_config_node *make_text_node(struct dm_config_tree *cft,
|
||||
|
||||
@@ -160,12 +160,18 @@ static int _parse_one(log_state *s, int outlet, const char *type, int enable)
|
||||
if (!strcmp(type, "all"))
|
||||
for (i = 0; i < 32; ++i)
|
||||
daemon_log_enable(s, outlet, i, enable);
|
||||
else if (!strcmp(type, "fatal"))
|
||||
daemon_log_enable(s, outlet, DAEMON_LOG_FATAL, enable);
|
||||
else if (!strcmp(type, "error"))
|
||||
daemon_log_enable(s, outlet, DAEMON_LOG_ERROR, enable);
|
||||
else if (!strcmp(type, "warn"))
|
||||
daemon_log_enable(s, outlet, DAEMON_LOG_WARN, enable);
|
||||
else if (!strcmp(type, "info"))
|
||||
daemon_log_enable(s, outlet, DAEMON_LOG_INFO, enable);
|
||||
else if (!strcmp(type, "wire"))
|
||||
daemon_log_enable(s, outlet, DAEMON_LOG_WIRE, enable);
|
||||
else if (!strcmp(type, "debug"))
|
||||
daemon_log_enable(s, outlet, DAEMON_LOG_DEBUG, enable);
|
||||
else
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -262,7 +262,6 @@ dm_tree_node_set_thin_external_origin
|
||||
dm_tree_node_set_thin_pool_discard
|
||||
dm_tree_node_set_thin_pool_error_if_no_space
|
||||
dm_tree_node_set_udev_flags
|
||||
dm_tree_node_size_changed
|
||||
dm_tree_preload_children
|
||||
dm_tree_retry_remove
|
||||
dm_tree_set_cookie
|
||||
|
||||
3
libdm/.exported_symbols.DM_1_02_110
Normal file
3
libdm/.exported_symbols.DM_1_02_110
Normal file
@@ -0,0 +1,3 @@
|
||||
dm_report_compact_given_fields
|
||||
dm_hold_control_dev
|
||||
dm_tree_node_size_changed
|
||||
@@ -21,13 +21,14 @@ SOURCES =\
|
||||
datastruct/hash.c \
|
||||
datastruct/list.c \
|
||||
libdm-common.c \
|
||||
libdm-file.c \
|
||||
libdm-deptree.c \
|
||||
libdm-string.c \
|
||||
libdm-report.c \
|
||||
libdm-timestamp.c \
|
||||
libdm-stats.c \
|
||||
libdm-config.c \
|
||||
libdm-deptree.c \
|
||||
libdm-file.c \
|
||||
libdm-report.c \
|
||||
libdm-stats.c \
|
||||
libdm-string.c \
|
||||
libdm-targets.c \
|
||||
libdm-timestamp.c \
|
||||
mm/dbg_malloc.c \
|
||||
mm/pool.c \
|
||||
regex/matcher.c \
|
||||
|
||||
@@ -81,6 +81,7 @@ static dm_bitset_t _dm_bitset = NULL;
|
||||
static uint32_t _dm_device_major = 0;
|
||||
|
||||
static int _control_fd = -1;
|
||||
static int _hold_control_fd_open = 0;
|
||||
static int _version_checked = 0;
|
||||
static int _version_ok = 1;
|
||||
static unsigned _ioctl_buffer_double_factor = 0;
|
||||
@@ -1201,8 +1202,13 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
|
||||
if (dmt->type == DM_DEVICE_SUSPEND)
|
||||
dmi->flags |= DM_SUSPEND_FLAG;
|
||||
if (dmt->no_flush)
|
||||
dmi->flags |= DM_NOFLUSH_FLAG;
|
||||
if (dmt->no_flush) {
|
||||
if (_dm_version_minor < 12)
|
||||
log_verbose("No flush flag unsupported by kernel. "
|
||||
"Buffers will be flushed.");
|
||||
else
|
||||
dmi->flags |= DM_NOFLUSH_FLAG;
|
||||
}
|
||||
if (dmt->read_only)
|
||||
dmi->flags |= DM_READONLY_FLAG;
|
||||
if (dmt->skip_lockfs)
|
||||
@@ -2079,9 +2085,18 @@ repeat_ioctl:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dm_hold_control_dev(int hold_open)
|
||||
{
|
||||
_hold_control_fd_open = hold_open ? 1 : 0;
|
||||
|
||||
log_debug("Hold of control device is now %sset.",
|
||||
_hold_control_fd_open ? "" : "un");
|
||||
}
|
||||
|
||||
void dm_lib_release(void)
|
||||
{
|
||||
_close_control_fd();
|
||||
if (!_hold_control_fd_open)
|
||||
_close_control_fd();
|
||||
dm_timestamp_destroy(_dm_ioctl_timestamp);
|
||||
_dm_ioctl_timestamp = NULL;
|
||||
update_devs();
|
||||
|
||||
@@ -352,6 +352,7 @@ struct dm_status_snapshot {
|
||||
unsigned has_metadata_sectors : 1; /* set when metadata_sectors is present */
|
||||
unsigned invalid : 1; /* set when snapshot is invalidated */
|
||||
unsigned merge_failed : 1; /* set when snapshot merge failed */
|
||||
unsigned overflow : 1; /* set when snapshot overflows */
|
||||
};
|
||||
|
||||
int dm_get_status_snapshot(struct dm_pool *mem, const char *params,
|
||||
@@ -1167,6 +1168,9 @@ void dm_lib_init(void) __attribute__((constructor));
|
||||
void dm_lib_release(void);
|
||||
void dm_lib_exit(void) __attribute__((destructor));
|
||||
|
||||
/* An optimisation for clients making repeated calls involving dm ioctls */
|
||||
void dm_hold_control_dev(int hold_open);
|
||||
|
||||
/*
|
||||
* Use NULL for all devices.
|
||||
*/
|
||||
@@ -1252,6 +1256,11 @@ const char *dm_tree_node_get_name(const struct dm_tree_node *node);
|
||||
const char *dm_tree_node_get_uuid(const struct dm_tree_node *node);
|
||||
const struct dm_info *dm_tree_node_get_info(const struct dm_tree_node *node);
|
||||
void *dm_tree_node_get_context(const struct dm_tree_node *node);
|
||||
/*
|
||||
* Returns 0 when node size and its children is unchanged.
|
||||
* Returns 1 when node or any of its children has increased size.
|
||||
* Rerurns -1 when node or any of its children has reduced size.
|
||||
*/
|
||||
int dm_tree_node_size_changed(const struct dm_tree_node *dnode);
|
||||
|
||||
/*
|
||||
@@ -2547,6 +2556,13 @@ int dm_report_object_is_selected(struct dm_report *rh, void *object, int do_outp
|
||||
*/
|
||||
int dm_report_compact_fields(struct dm_report *rh);
|
||||
|
||||
/*
|
||||
* The same as dm_report_compact_fields, but for selected fields only.
|
||||
* The "fields" arg is comma separated list of field names (the same format
|
||||
* as used for "output_fields" arg in dm_report_init fn).
|
||||
*/
|
||||
int dm_report_compact_given_fields(struct dm_report *rh, const char *fields);
|
||||
|
||||
/*
|
||||
* Returns 1 if there is no data waiting to be output.
|
||||
*/
|
||||
|
||||
@@ -1038,7 +1038,7 @@ static int _rm_dev_node(const char *dev_name, int warn_if_udev_failed)
|
||||
|
||||
if (!_build_dev_path(path, sizeof(path), dev_name))
|
||||
return_0;
|
||||
if (stat(path, &info) < 0)
|
||||
if (lstat(path, &info) < 0)
|
||||
return 1;
|
||||
else if (_warn_if_op_needed(warn_if_udev_failed))
|
||||
log_warn("Node %s was not removed by udev. "
|
||||
@@ -1060,20 +1060,31 @@ static int _rename_dev_node(const char *old_name, const char *new_name,
|
||||
{
|
||||
char oldpath[PATH_MAX];
|
||||
char newpath[PATH_MAX];
|
||||
struct stat info;
|
||||
struct stat info, info2;
|
||||
struct stat *info_block_dev;
|
||||
|
||||
if (!_build_dev_path(oldpath, sizeof(oldpath), old_name) ||
|
||||
!_build_dev_path(newpath, sizeof(newpath), new_name))
|
||||
return_0;
|
||||
|
||||
if (stat(newpath, &info) == 0) {
|
||||
if (!S_ISBLK(info.st_mode)) {
|
||||
if (lstat(newpath, &info) == 0) {
|
||||
if (S_ISLNK(info.st_mode)) {
|
||||
if (stat(newpath, &info2) == 0)
|
||||
info_block_dev = &info2;
|
||||
else {
|
||||
log_sys_error("stat", newpath);
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
info_block_dev = &info;
|
||||
|
||||
if (!S_ISBLK(info_block_dev->st_mode)) {
|
||||
log_error("A non-block device file at '%s' "
|
||||
"is already present", newpath);
|
||||
return 0;
|
||||
}
|
||||
else if (_warn_if_op_needed(warn_if_udev_failed)) {
|
||||
if (stat(oldpath, &info) < 0 &&
|
||||
if (lstat(oldpath, &info) < 0 &&
|
||||
errno == ENOENT)
|
||||
/* assume udev already deleted this */
|
||||
return 1;
|
||||
|
||||
@@ -51,4 +51,6 @@ void selinux_release(void);
|
||||
void inc_suspended(void);
|
||||
void dec_suspended(void);
|
||||
|
||||
int parse_thin_pool_status(const char *params, struct dm_status_thin_pool *s);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -157,21 +157,18 @@ struct dm_config_tree *dm_config_insert_cascaded_tree(struct dm_config_tree *fir
|
||||
|
||||
static struct dm_config_node *_config_reverse(struct dm_config_node *head)
|
||||
{
|
||||
if (!head)
|
||||
return NULL;
|
||||
|
||||
struct dm_config_node *left = head, *middle = NULL, *right = NULL;
|
||||
|
||||
do {
|
||||
while (left) {
|
||||
right = middle;
|
||||
middle = left;
|
||||
left = left->sib;
|
||||
middle->sib = right;
|
||||
middle->child = _config_reverse(middle->child);
|
||||
} while (left);
|
||||
}
|
||||
|
||||
return middle;
|
||||
};
|
||||
}
|
||||
|
||||
int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2014 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
@@ -86,7 +86,7 @@ static const struct {
|
||||
{ SEG_RAID6_NC, "raid6_nc"},
|
||||
|
||||
/*
|
||||
*WARNING: Since 'raid' target overloads this 1:1 mapping table
|
||||
* WARNING: Since 'raid' target overloads this 1:1 mapping table
|
||||
* for search do not add new enum elements past them!
|
||||
*/
|
||||
{ SEG_RAID5_LS, "raid5"}, /* same as "raid5_ls" (default for MD also) */
|
||||
@@ -220,7 +220,7 @@ struct load_properties {
|
||||
uint32_t read_ahead_flags;
|
||||
|
||||
unsigned segment_count;
|
||||
unsigned size_changed;
|
||||
int size_changed;
|
||||
struct dm_list segs;
|
||||
|
||||
const char *new_name;
|
||||
@@ -1427,48 +1427,6 @@ static int _suspend_node(const char *name, uint32_t major, uint32_t minor,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _thin_pool_parse_status(const char *params,
|
||||
struct dm_status_thin_pool *s)
|
||||
{
|
||||
int pos;
|
||||
|
||||
if (!params) {
|
||||
log_error("Failed to parse invalid thin params.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: add support for held metadata root */
|
||||
if (sscanf(params, FMTu64 " " FMTu64 "/" FMTu64 " " FMTu64 "/" FMTu64 "%n",
|
||||
&s->transaction_id,
|
||||
&s->used_metadata_blocks,
|
||||
&s->total_metadata_blocks,
|
||||
&s->used_data_blocks,
|
||||
&s->total_data_blocks, &pos) < 5) {
|
||||
log_error("Failed to parse thin pool params: %s.", params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* New status flags */
|
||||
if (strstr(params + pos, "no_discard_passdown"))
|
||||
s->discards = DM_THIN_DISCARDS_NO_PASSDOWN;
|
||||
else if (strstr(params + pos, "ignore_discard"))
|
||||
s->discards = DM_THIN_DISCARDS_IGNORE;
|
||||
else /* default discard_passdown */
|
||||
s->discards = DM_THIN_DISCARDS_PASSDOWN;
|
||||
|
||||
if (strstr(params + pos, "ro "))
|
||||
s->read_only = 1;
|
||||
else if (strstr(params + pos, "fail"))
|
||||
s->fail = 1;
|
||||
else if (strstr(params + pos, "out_of_data_space"))
|
||||
s->out_of_data_space = 1;
|
||||
|
||||
if (strstr(params + pos, "error_if_no_space"))
|
||||
s->error_if_no_space = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _thin_pool_get_status(struct dm_tree_node *dnode,
|
||||
struct dm_status_thin_pool *s)
|
||||
{
|
||||
@@ -1501,7 +1459,7 @@ static int _thin_pool_get_status(struct dm_tree_node *dnode,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!_thin_pool_parse_status(params, s))
|
||||
if (!parse_thin_pool_status(params, s))
|
||||
goto_out;
|
||||
|
||||
log_debug_activation("Found transaction id %" PRIu64 " for thin pool %s "
|
||||
@@ -2370,6 +2328,20 @@ static int _mirror_emit_segment_line(struct dm_task *dmt, struct load_segment *s
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Is parameter non-zero? */
|
||||
#define PARAM_IS_SET(p) ((p) ? 1 : 0)
|
||||
|
||||
/* Return number of bits assuming 4 * 64 bit size */
|
||||
static int _get_params_count(uint64_t bits)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
r += 2 * hweight32(bits & 0xFFFFFFFF);
|
||||
r += 2 * hweight32(bits >> 32);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _raid_emit_segment_line(struct dm_task *dmt, uint32_t major,
|
||||
uint32_t minor, struct load_segment *seg,
|
||||
uint64_t *seg_start, char *params,
|
||||
@@ -2382,25 +2354,14 @@ static int _raid_emit_segment_line(struct dm_task *dmt, uint32_t major,
|
||||
if ((seg->flags & DM_NOSYNC) || (seg->flags & DM_FORCESYNC))
|
||||
param_count++;
|
||||
|
||||
if (seg->region_size)
|
||||
param_count += 2;
|
||||
param_count += 2 * (PARAM_IS_SET(seg->region_size) +
|
||||
PARAM_IS_SET(seg->writebehind) +
|
||||
PARAM_IS_SET(seg->min_recovery_rate) +
|
||||
PARAM_IS_SET(seg->max_recovery_rate));
|
||||
|
||||
if (seg->writebehind)
|
||||
param_count += 2;
|
||||
|
||||
if (seg->min_recovery_rate)
|
||||
param_count += 2;
|
||||
|
||||
if (seg->max_recovery_rate)
|
||||
param_count += 2;
|
||||
|
||||
/* rebuilds is 64-bit */
|
||||
param_count += 2 * hweight32(seg->rebuilds & 0xFFFFFFFF);
|
||||
param_count += 2 * hweight32(seg->rebuilds >> 32);
|
||||
|
||||
/* rebuilds is 64-bit */
|
||||
param_count += 2 * hweight32(seg->writemostly & 0xFFFFFFFF);
|
||||
param_count += 2 * hweight32(seg->writemostly >> 32);
|
||||
/* rebuilds and writemostly are 64 bits */
|
||||
param_count += _get_params_count(seg->rebuilds);
|
||||
param_count += _get_params_count(seg->writemostly);
|
||||
|
||||
if ((seg->type == SEG_RAID1) && seg->stripe_size)
|
||||
log_error("WARNING: Ignoring RAID1 stripe size");
|
||||
@@ -2420,13 +2381,6 @@ static int _raid_emit_segment_line(struct dm_task *dmt, uint32_t major,
|
||||
if (seg->rebuilds & (1ULL << i))
|
||||
EMIT_PARAMS(pos, " rebuild %u", i);
|
||||
|
||||
for (i = 0; i < (seg->area_count / 2); i++)
|
||||
if (seg->writemostly & (1ULL << i))
|
||||
EMIT_PARAMS(pos, " write_mostly %u", i);
|
||||
|
||||
if (seg->writebehind)
|
||||
EMIT_PARAMS(pos, " writebehind %u", seg->writebehind);
|
||||
|
||||
if (seg->min_recovery_rate)
|
||||
EMIT_PARAMS(pos, " min_recovery_rate %u",
|
||||
seg->min_recovery_rate);
|
||||
@@ -2435,6 +2389,13 @@ static int _raid_emit_segment_line(struct dm_task *dmt, uint32_t major,
|
||||
EMIT_PARAMS(pos, " max_recovery_rate %u",
|
||||
seg->max_recovery_rate);
|
||||
|
||||
for (i = 0; i < (seg->area_count / 2); i++)
|
||||
if (seg->writemostly & (1ULL << i))
|
||||
EMIT_PARAMS(pos, " write_mostly %u", i);
|
||||
|
||||
if (seg->writebehind)
|
||||
EMIT_PARAMS(pos, " max_write_behind %u", seg->writebehind);
|
||||
|
||||
/* Print number of metadata/data device pairs */
|
||||
EMIT_PARAMS(pos, " %u", seg->area_count/2);
|
||||
|
||||
@@ -2768,7 +2729,8 @@ static int _load_node(struct dm_tree_node *dnode)
|
||||
|
||||
existing_table_size = dm_task_get_existing_table_size(dmt);
|
||||
if ((dnode->props.size_changed =
|
||||
(existing_table_size == seg_start) ? 0 : 1)) {
|
||||
(existing_table_size == seg_start) ? 0 :
|
||||
(existing_table_size > seg_start) ? -1 : 1)) {
|
||||
/*
|
||||
* Kernel usually skips size validation on zero-length devices
|
||||
* now so no need to preload them.
|
||||
@@ -2864,8 +2826,10 @@ int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
}
|
||||
|
||||
/* Propagate device size change change */
|
||||
if (child->props.size_changed)
|
||||
if (child->props.size_changed > 0 && !dnode->props.size_changed)
|
||||
dnode->props.size_changed = 1;
|
||||
else if (child->props.size_changed < 0)
|
||||
dnode->props.size_changed = -1;
|
||||
|
||||
/* Resume device immediately if it has parents and its size changed */
|
||||
if (!dm_tree_node_num_children(child, 1) || !child->props.size_changed)
|
||||
@@ -3100,43 +3064,6 @@ int dm_tree_node_add_snapshot_merge_target(struct dm_tree_node *node,
|
||||
merge_uuid, 1, chunk_size);
|
||||
}
|
||||
|
||||
int dm_get_status_snapshot(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_snapshot **status)
|
||||
{
|
||||
struct dm_status_snapshot *s;
|
||||
int r;
|
||||
|
||||
if (!params) {
|
||||
log_error("Failed to parse invalid snapshot params.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(*s)))) {
|
||||
log_error("Failed to allocate snapshot status structure.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sscanf(params, FMTu64 "/" FMTu64 " " FMTu64,
|
||||
&s->used_sectors, &s->total_sectors,
|
||||
&s->metadata_sectors);
|
||||
|
||||
if (r == 3 || r == 2)
|
||||
s->has_metadata_sectors = (r == 3);
|
||||
else if (!strcmp(params, "Invalid"))
|
||||
s->invalid = 1;
|
||||
else if (!strcmp(params, "Merge failed"))
|
||||
s->merge_failed = 1;
|
||||
else {
|
||||
dm_pool_free(mem, s);
|
||||
log_error("Failed to parse snapshot params: %s.", params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_tree_node_add_error_target(struct dm_tree_node *node,
|
||||
uint64_t size)
|
||||
{
|
||||
@@ -3308,84 +3235,6 @@ int dm_tree_node_add_raid_target(struct dm_tree_node *node,
|
||||
return dm_tree_node_add_raid_target_with_params(node, size, ¶ms);
|
||||
}
|
||||
|
||||
/*
|
||||
* Various RAID status versions include:
|
||||
* Versions < 1.5.0 (4 fields):
|
||||
* <raid_type> <#devs> <health_str> <sync_ratio>
|
||||
* Versions 1.5.0+ (6 fields):
|
||||
* <raid_type> <#devs> <health_str> <sync_ratio> <sync_action> <mismatch_cnt>
|
||||
*/
|
||||
int dm_get_status_raid(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_raid **status)
|
||||
{
|
||||
int i;
|
||||
const char *pp, *p;
|
||||
struct dm_status_raid *s;
|
||||
|
||||
if (!params || !(p = strchr(params, ' '))) {
|
||||
log_error("Failed to parse invalid raid params.");
|
||||
return 0;
|
||||
}
|
||||
p++;
|
||||
|
||||
/* second field holds the device count */
|
||||
if (sscanf(p, "%d", &i) != 1)
|
||||
return_0;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid))))
|
||||
return_0;
|
||||
|
||||
if (!(s->raid_type = dm_pool_zalloc(mem, p - params)))
|
||||
goto_bad; /* memory is freed went pool is destroyed */
|
||||
|
||||
if (!(s->dev_health = dm_pool_zalloc(mem, i + 1)))
|
||||
goto_bad;
|
||||
|
||||
if (sscanf(params, "%s %u %s %" PRIu64 "/%" PRIu64,
|
||||
s->raid_type,
|
||||
&s->dev_count,
|
||||
s->dev_health,
|
||||
&s->insync_regions,
|
||||
&s->total_regions) != 5) {
|
||||
log_error("Failed to parse raid params: %s", params);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
|
||||
/*
|
||||
* All pre-1.5.0 version parameters are read. Now we check
|
||||
* for additional 1.5.0+ parameters.
|
||||
*
|
||||
* Note that 'sync_action' will be NULL (and mismatch_count
|
||||
* will be 0) if the kernel returns a pre-1.5.0 status.
|
||||
*/
|
||||
for (p = params, i = 0; i < 4; i++, p++)
|
||||
if (!(p = strchr(p, ' ')))
|
||||
return 1; /* return pre-1.5.0 status */
|
||||
|
||||
pp = p;
|
||||
if (!(p = strchr(p, ' '))) {
|
||||
log_error(INTERNAL_ERROR "Bad RAID status received.");
|
||||
goto bad;
|
||||
}
|
||||
p++;
|
||||
|
||||
if (!(s->sync_action = dm_pool_zalloc(mem, p - pp)))
|
||||
goto_bad;
|
||||
|
||||
if (sscanf(pp, "%s %" PRIu64, s->sync_action, &s->mismatch_count) != 2) {
|
||||
log_error("Failed to parse raid params: %s", params);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
dm_pool_free(mem, s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dm_tree_node_add_cache_target(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
uint64_t feature_flags, /* DM_CACHE_FEATURE_* */
|
||||
@@ -3456,7 +3305,8 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
|
||||
return_0;
|
||||
|
||||
seg->data_block_size = data_block_size;
|
||||
seg->flags = feature_flags;
|
||||
/* Enforce WriteThough mode for cleaner policy */
|
||||
seg->flags = (strcmp(policy_name, "cleaner") == 0) ? DM_CACHE_FEATURE_WRITETHROUGH : feature_flags;
|
||||
seg->policy_name = policy_name;
|
||||
|
||||
/* FIXME: better validation missing */
|
||||
@@ -3477,143 +3327,6 @@ int dm_tree_node_add_cache_target(struct dm_tree_node *node,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *advance_to_next_word(const char *str, int count)
|
||||
{
|
||||
int i;
|
||||
const char *p;
|
||||
|
||||
for (p = str, i = 0; i < count; i++, p++)
|
||||
if (!(p = strchr(p, ' ')))
|
||||
return NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* <metadata block size> <#used metadata blocks>/<#total metadata blocks>
|
||||
* <cache block size> <#used cache blocks>/<#total cache blocks>
|
||||
* <#read hits> <#read misses> <#write hits> <#write misses>
|
||||
* <#demotions> <#promotions> <#dirty> <#features> <features>*
|
||||
* <#core args> <core args>* <policy name> <#policy args> <policy args>*
|
||||
*
|
||||
* metadata block size : Fixed block size for each metadata block in
|
||||
* sectors
|
||||
* #used metadata blocks : Number of metadata blocks used
|
||||
* #total metadata blocks : Total number of metadata blocks
|
||||
* cache block size : Configurable block size for the cache device
|
||||
* in sectors
|
||||
* #used cache blocks : Number of blocks resident in the cache
|
||||
* #total cache blocks : Total number of cache blocks
|
||||
* #read hits : Number of times a READ bio has been mapped
|
||||
* to the cache
|
||||
* #read misses : Number of times a READ bio has been mapped
|
||||
* to the origin
|
||||
* #write hits : Number of times a WRITE bio has been mapped
|
||||
* to the cache
|
||||
* #write misses : Number of times a WRITE bio has been
|
||||
* mapped to the origin
|
||||
* #demotions : Number of times a block has been removed
|
||||
* from the cache
|
||||
* #promotions : Number of times a block has been moved to
|
||||
* the cache
|
||||
* #dirty : Number of blocks in the cache that differ
|
||||
* from the origin
|
||||
* #feature args : Number of feature args to follow
|
||||
* feature args : 'writethrough' (optional)
|
||||
* #core args : Number of core arguments (must be even)
|
||||
* core args : Key/value pairs for tuning the core
|
||||
* e.g. migration_threshold
|
||||
* *policy name : Name of the policy
|
||||
* #policy args : Number of policy arguments to follow (must be even)
|
||||
* policy args : Key/value pairs
|
||||
* e.g. sequential_threshold
|
||||
*/
|
||||
int dm_get_status_cache(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_cache **status)
|
||||
{
|
||||
int i, feature_argc;
|
||||
char *str;
|
||||
const char *p, *pp;
|
||||
struct dm_status_cache *s;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_cache))))
|
||||
return_0;
|
||||
|
||||
/* Read in args that have definitive placement */
|
||||
if (sscanf(params,
|
||||
" %" PRIu32
|
||||
" %" PRIu64 "/%" PRIu64
|
||||
" %" PRIu32
|
||||
" %" PRIu64 "/%" PRIu64
|
||||
" %" PRIu64 " %" PRIu64
|
||||
" %" PRIu64 " %" PRIu64
|
||||
" %" PRIu64 " %" PRIu64
|
||||
" %" PRIu64
|
||||
" %d",
|
||||
&s->metadata_block_size,
|
||||
&s->metadata_used_blocks, &s->metadata_total_blocks,
|
||||
&s->block_size, /* AKA, chunk_size */
|
||||
&s->used_blocks, &s->total_blocks,
|
||||
&s->read_hits, &s->read_misses,
|
||||
&s->write_hits, &s->write_misses,
|
||||
&s->demotions, &s->promotions,
|
||||
&s->dirty_blocks,
|
||||
&feature_argc) != 14)
|
||||
goto bad;
|
||||
|
||||
/* Now jump to "features" section */
|
||||
if (!(p = advance_to_next_word(params, 12)))
|
||||
goto bad;
|
||||
|
||||
/* Read in features */
|
||||
for (i = 0; i < feature_argc; i++) {
|
||||
if (!strncmp(p, "writethrough ", 13))
|
||||
s->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
else if (!strncmp(p, "writeback ", 10))
|
||||
s->feature_flags |= DM_CACHE_FEATURE_WRITEBACK;
|
||||
else
|
||||
log_error("Unknown feature in status: %s", params);
|
||||
|
||||
if (!(p = advance_to_next_word(p, 1)))
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Read in core_args. */
|
||||
if (sscanf(p, "%d ", &s->core_argc) != 1)
|
||||
goto bad;
|
||||
if (s->core_argc &&
|
||||
(!(s->core_argv = dm_pool_zalloc(mem, sizeof(char *) * s->core_argc)) ||
|
||||
!(p = advance_to_next_word(p, 1)) ||
|
||||
!(str = dm_pool_strdup(mem, p)) ||
|
||||
!(p = advance_to_next_word(p, s->core_argc)) ||
|
||||
(dm_split_words(str, s->core_argc, 0, s->core_argv) != s->core_argc)))
|
||||
goto bad;
|
||||
|
||||
/* Read in policy args */
|
||||
pp = p;
|
||||
if (!(p = advance_to_next_word(p, 1)) ||
|
||||
!(s->policy_name = dm_pool_zalloc(mem, (p - pp))))
|
||||
goto bad;
|
||||
if (sscanf(pp, "%s %d", s->policy_name, &s->policy_argc) != 2)
|
||||
goto bad;
|
||||
if (s->policy_argc &&
|
||||
(!(s->policy_argv = dm_pool_zalloc(mem, sizeof(char *) * s->policy_argc)) ||
|
||||
!(p = advance_to_next_word(p, 1)) ||
|
||||
!(str = dm_pool_strdup(mem, p)) ||
|
||||
(dm_split_words(str, s->policy_argc, 0, s->policy_argv) != s->policy_argc)))
|
||||
goto bad;
|
||||
|
||||
*status = s;
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
log_error("Failed to parse cache params: %s", params);
|
||||
dm_pool_free(mem, s);
|
||||
*status = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dm_tree_node_add_replicator_target(struct dm_tree_node *node,
|
||||
uint64_t size,
|
||||
const char *rlog_uuid,
|
||||
@@ -4040,52 +3753,6 @@ int dm_tree_node_set_thin_external_origin(struct dm_tree_node *node,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_get_status_thin_pool(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_thin_pool **status)
|
||||
{
|
||||
struct dm_status_thin_pool *s;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_thin_pool)))) {
|
||||
log_error("Failed to allocate thin_pool status structure.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_thin_pool_parse_status(params, s)) {
|
||||
dm_pool_free(mem, s);
|
||||
return_0;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_get_status_thin(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_thin **status)
|
||||
{
|
||||
struct dm_status_thin *s;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_thin)))) {
|
||||
log_error("Failed to allocate thin status structure.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strchr(params, '-')) {
|
||||
s->mapped_sectors = 0;
|
||||
s->highest_mapped_sector = 0;
|
||||
} else if (sscanf(params, FMTu64 " " FMTu64,
|
||||
&s->mapped_sectors,
|
||||
&s->highest_mapped_sector) != 2) {
|
||||
dm_pool_free(mem, s);
|
||||
log_error("Failed to parse thin params: %s.", params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _add_area(struct dm_tree_node *node, struct load_segment *seg, struct dm_tree_node *dev_node, uint64_t offset)
|
||||
{
|
||||
struct seg_area *area;
|
||||
@@ -4189,3 +3856,19 @@ void dm_tree_node_set_callback(struct dm_tree_node *dnode,
|
||||
dnode->callback = cb;
|
||||
dnode->callback_data = data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Backward compatible dm_tree_node_size_changed() implementations.
|
||||
*
|
||||
* Keep these at the end of the file to avoid adding clutter around the
|
||||
* current dm_tree_node_size_changed() version.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
int dm_tree_node_size_changed_base(const struct dm_tree_node *dnode);
|
||||
DM_EXPORT_SYMBOL_BASE(dm_tree_node_size_changed);
|
||||
int dm_tree_node_size_changed_base(const struct dm_tree_node *dnode)
|
||||
{
|
||||
/* Base does not make difference between smaller and bigger */
|
||||
return dm_tree_node_size_changed(dnode) ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -19,6 +19,24 @@
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
|
||||
static int _is_dir(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(path, &st) < 0) {
|
||||
log_sys_error("stat", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
log_error("Existing path %s is not "
|
||||
"a directory.", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _create_dir_recursive(const char *dir)
|
||||
{
|
||||
char *orig, *s;
|
||||
@@ -36,10 +54,15 @@ static int _create_dir_recursive(const char *dir)
|
||||
*s = '\0';
|
||||
if (*orig) {
|
||||
rc = mkdir(orig, 0777);
|
||||
if (rc < 0 && errno != EEXIST) {
|
||||
if (errno != EROFS)
|
||||
log_sys_error("mkdir", orig);
|
||||
goto out;
|
||||
if (rc < 0) {
|
||||
if (errno == EEXIST) {
|
||||
if (!_is_dir(orig))
|
||||
goto_out;
|
||||
} else {
|
||||
if (errno != EROFS)
|
||||
log_sys_error("mkdir", orig);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
*s++ = '/';
|
||||
@@ -47,10 +70,15 @@ static int _create_dir_recursive(const char *dir)
|
||||
|
||||
/* Create final directory */
|
||||
rc = mkdir(dir, 0777);
|
||||
if (rc < 0 && errno != EEXIST) {
|
||||
if (errno != EROFS)
|
||||
log_sys_error("mkdir", orig);
|
||||
goto out;
|
||||
if (rc < 0) {
|
||||
if (errno == EEXIST) {
|
||||
if (!_is_dir(dir))
|
||||
goto_out;
|
||||
} else {
|
||||
if (errno != EROFS)
|
||||
log_sys_error("mkdir", orig);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
r = 1;
|
||||
@@ -66,14 +94,15 @@ int dm_create_dir(const char *dir)
|
||||
if (!*dir)
|
||||
return 1;
|
||||
|
||||
if (stat(dir, &info) < 0)
|
||||
return _create_dir_recursive(dir);
|
||||
|
||||
if (S_ISDIR(info.st_mode))
|
||||
if (stat(dir, &info) == 0 && S_ISDIR(info.st_mode))
|
||||
return 1;
|
||||
|
||||
log_error("Directory \"%s\" not found", dir);
|
||||
return 0;
|
||||
if (!_create_dir_recursive(dir)) {
|
||||
log_error("Failed to create directory %s.", dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_is_empty_dir(const char *dir)
|
||||
|
||||
@@ -81,6 +81,7 @@ struct dm_report {
|
||||
#define FLD_ASCENDING 0x00004000
|
||||
#define FLD_DESCENDING 0x00008000
|
||||
#define FLD_COMPACTED 0x00010000
|
||||
#define FLD_COMPACT_ONE 0x00020000
|
||||
|
||||
struct field_properties {
|
||||
struct dm_list list;
|
||||
@@ -1644,11 +1645,21 @@ static int _cmp_field_time(struct dm_report *rh,
|
||||
static int _cmp_field_string_list_strict_all(const struct str_list_sort_value *val,
|
||||
const struct selection_str_list *sel)
|
||||
{
|
||||
unsigned int sel_list_size = dm_list_size(sel->list);
|
||||
struct dm_str_list *sel_item;
|
||||
unsigned int i = 1;
|
||||
|
||||
if (!val->items[0].len) {
|
||||
if (sel_list_size == 1) {
|
||||
/* match blank string list with selection defined as blank string only */
|
||||
sel_item = dm_list_item(dm_list_first(sel->list), struct dm_str_list);
|
||||
return !strcmp(sel_item->str, "");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if item count differs, it's clear the lists do not match */
|
||||
if (val->items[0].len != dm_list_size(sel->list))
|
||||
if (val->items[0].len != sel_list_size)
|
||||
return 0;
|
||||
|
||||
/* both lists are sorted so they either match 1:1 or not */
|
||||
@@ -1666,15 +1677,21 @@ static int _cmp_field_string_list_strict_all(const struct str_list_sort_value *v
|
||||
static int _cmp_field_string_list_subset_all(const struct str_list_sort_value *val,
|
||||
const struct selection_str_list *sel)
|
||||
{
|
||||
unsigned int sel_list_size = dm_list_size(sel->list);
|
||||
struct dm_str_list *sel_item;
|
||||
unsigned int i, last_found = 1;
|
||||
int r = 0;
|
||||
|
||||
/* if value has no items and selection has at leas one, it's clear there's no match */
|
||||
if ((val->items[0].len == 0) && dm_list_size(sel->list))
|
||||
if (!val->items[0].len) {
|
||||
if (sel_list_size == 1) {
|
||||
/* match blank string list with selection defined as blank string only */
|
||||
sel_item = dm_list_item(dm_list_first(sel->list), struct dm_str_list);
|
||||
return !strcmp(sel_item->str, "");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check selection is a subset of the value. */
|
||||
/* check selection is a subset of the value */
|
||||
dm_list_iterate_items(sel_item, sel->list) {
|
||||
r = 0;
|
||||
for (i = last_found; i <= val->items[0].len; i++) {
|
||||
@@ -1698,9 +1715,14 @@ static int _cmp_field_string_list_any(const struct str_list_sort_value *val,
|
||||
struct dm_str_list *sel_item;
|
||||
unsigned int i;
|
||||
|
||||
/* if value has no items and selection has at least one, it's clear there's no match */
|
||||
if ((val->items[0].len == 0) && dm_list_size(sel->list))
|
||||
/* match blank string list with selection that contains blank string */
|
||||
if (!val->items[0].len) {
|
||||
dm_list_iterate_items(sel_item, sel->list) {
|
||||
if (!strcmp(sel_item->str, ""))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(sel_item, sel->list) {
|
||||
/*
|
||||
@@ -1992,7 +2014,7 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
int dm_report_compact_fields(struct dm_report *rh)
|
||||
static int _do_report_compact_fields(struct dm_report *rh, int global)
|
||||
{
|
||||
struct dm_report_field *field;
|
||||
struct field_properties *fp;
|
||||
@@ -2015,7 +2037,9 @@ int dm_report_compact_fields(struct dm_report *rh)
|
||||
* in next step...
|
||||
*/
|
||||
dm_list_iterate_items(fp, &rh->field_props) {
|
||||
if (!(fp->flags & FLD_HIDDEN))
|
||||
if (fp->flags & FLD_HIDDEN)
|
||||
continue;
|
||||
if (global || (fp->flags & FLD_COMPACT_ONE))
|
||||
fp->flags |= (FLD_COMPACTED | FLD_HIDDEN);
|
||||
}
|
||||
|
||||
@@ -2044,6 +2068,61 @@ int dm_report_compact_fields(struct dm_report *rh)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_compact_fields(struct dm_report *rh)
|
||||
{
|
||||
return _do_report_compact_fields(rh, 1);
|
||||
}
|
||||
|
||||
static int _field_to_compact_match(struct dm_report *rh, const char *field, size_t flen)
|
||||
{
|
||||
struct field_properties *fp;
|
||||
uint32_t f;
|
||||
int implicit;
|
||||
|
||||
if ((_get_field(rh, field, flen, &f, &implicit))) {
|
||||
dm_list_iterate_items(fp, &rh->field_props) {
|
||||
if ((fp->implicit == implicit) && (fp->field_num == f)) {
|
||||
fp->flags |= FLD_COMPACT_ONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _parse_fields_to_compact(struct dm_report *rh, const char *fields)
|
||||
{
|
||||
const char *ws; /* Word start */
|
||||
const char *we = fields; /* Word end */
|
||||
|
||||
if (!fields)
|
||||
return 1;
|
||||
|
||||
while (*we) {
|
||||
while (*we && *we == ',')
|
||||
we++;
|
||||
ws = we;
|
||||
while (*we && *we != ',')
|
||||
we++;
|
||||
if (!_field_to_compact_match(rh, ws, (size_t) (we - ws))) {
|
||||
log_error("dm_report: Unrecognized field: %.*s", (int) (we - ws), ws);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_compact_given_fields(struct dm_report *rh, const char *fields)
|
||||
{
|
||||
if (!_parse_fields_to_compact(rh, fields))
|
||||
return_0;
|
||||
|
||||
return _do_report_compact_fields(rh, 0);
|
||||
}
|
||||
|
||||
int dm_report_object(struct dm_report *rh, void *object)
|
||||
{
|
||||
return _do_report_object(rh, object, 1, NULL);
|
||||
@@ -2460,11 +2539,8 @@ static int _add_item_to_string_list(struct dm_pool *mem, const char *begin,
|
||||
{
|
||||
struct dm_str_list *item;
|
||||
|
||||
if (begin == end)
|
||||
return_0;
|
||||
|
||||
if (!(item = dm_pool_zalloc(mem, sizeof(*item))) ||
|
||||
!(item->str = dm_pool_strndup(mem, begin, end - begin))) {
|
||||
!(item->str = begin == end ? "" : dm_pool_strndup(mem, begin, end - begin))) {
|
||||
log_error("_add_item_to_string_list: memory allocation failed for string list item");
|
||||
return 0;
|
||||
}
|
||||
|
||||
357
libdm/libdm-targets.c
Normal file
357
libdm/libdm-targets.c
Normal file
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* 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
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "dmlib.h"
|
||||
#include "libdm-common.h"
|
||||
|
||||
int dm_get_status_snapshot(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_snapshot **status)
|
||||
{
|
||||
struct dm_status_snapshot *s;
|
||||
int r;
|
||||
|
||||
if (!params) {
|
||||
log_error("Failed to parse invalid snapshot params.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(*s)))) {
|
||||
log_error("Failed to allocate snapshot status structure.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sscanf(params, FMTu64 "/" FMTu64 " " FMTu64,
|
||||
&s->used_sectors, &s->total_sectors,
|
||||
&s->metadata_sectors);
|
||||
|
||||
if (r == 3 || r == 2)
|
||||
s->has_metadata_sectors = (r == 3);
|
||||
else if (!strcmp(params, "Invalid"))
|
||||
s->invalid = 1;
|
||||
else if (!strcmp(params, "Merge failed"))
|
||||
s->merge_failed = 1;
|
||||
else if (!strcmp(params, "Overflow"))
|
||||
s->overflow = 1;
|
||||
else {
|
||||
dm_pool_free(mem, s);
|
||||
log_error("Failed to parse snapshot params: %s.", params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Various RAID status versions include:
|
||||
* Versions < 1.5.0 (4 fields):
|
||||
* <raid_type> <#devs> <health_str> <sync_ratio>
|
||||
* Versions 1.5.0+ (6 fields):
|
||||
* <raid_type> <#devs> <health_str> <sync_ratio> <sync_action> <mismatch_cnt>
|
||||
*/
|
||||
int dm_get_status_raid(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_raid **status)
|
||||
{
|
||||
int i;
|
||||
const char *pp, *p;
|
||||
struct dm_status_raid *s;
|
||||
|
||||
if (!params || !(p = strchr(params, ' '))) {
|
||||
log_error("Failed to parse invalid raid params.");
|
||||
return 0;
|
||||
}
|
||||
p++;
|
||||
|
||||
/* second field holds the device count */
|
||||
if (sscanf(p, "%d", &i) != 1)
|
||||
return_0;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid))))
|
||||
return_0;
|
||||
|
||||
if (!(s->raid_type = dm_pool_zalloc(mem, p - params)))
|
||||
goto_bad; /* memory is freed when pool is destroyed */
|
||||
|
||||
if (!(s->dev_health = dm_pool_zalloc(mem, i + 1)))
|
||||
goto_bad;
|
||||
|
||||
if (sscanf(params, "%s %u %s %" PRIu64 "/%" PRIu64,
|
||||
s->raid_type,
|
||||
&s->dev_count,
|
||||
s->dev_health,
|
||||
&s->insync_regions,
|
||||
&s->total_regions) != 5) {
|
||||
log_error("Failed to parse raid params: %s", params);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
|
||||
/*
|
||||
* All pre-1.5.0 version parameters are read. Now we check
|
||||
* for additional 1.5.0+ parameters.
|
||||
*
|
||||
* Note that 'sync_action' will be NULL (and mismatch_count
|
||||
* will be 0) if the kernel returns a pre-1.5.0 status.
|
||||
*/
|
||||
for (p = params, i = 0; i < 4; i++, p++)
|
||||
if (!(p = strchr(p, ' ')))
|
||||
return 1; /* return pre-1.5.0 status */
|
||||
|
||||
pp = p;
|
||||
if (!(p = strchr(p, ' '))) {
|
||||
log_error(INTERNAL_ERROR "Bad RAID status received.");
|
||||
goto bad;
|
||||
}
|
||||
p++;
|
||||
|
||||
if (!(s->sync_action = dm_pool_zalloc(mem, p - pp)))
|
||||
goto_bad;
|
||||
|
||||
if (sscanf(pp, "%s %" PRIu64, s->sync_action, &s->mismatch_count) != 2) {
|
||||
log_error("Failed to parse raid params: %s", params);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
return 1;
|
||||
bad:
|
||||
dm_pool_free(mem, s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *_advance_to_next_word(const char *str, int count)
|
||||
{
|
||||
int i;
|
||||
const char *p;
|
||||
|
||||
for (p = str, i = 0; i < count; i++, p++)
|
||||
if (!(p = strchr(p, ' ')))
|
||||
return NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* <metadata block size> <#used metadata blocks>/<#total metadata blocks>
|
||||
* <cache block size> <#used cache blocks>/<#total cache blocks>
|
||||
* <#read hits> <#read misses> <#write hits> <#write misses>
|
||||
* <#demotions> <#promotions> <#dirty> <#features> <features>*
|
||||
* <#core args> <core args>* <policy name> <#policy args> <policy args>*
|
||||
*
|
||||
* metadata block size : Fixed block size for each metadata block in
|
||||
* sectors
|
||||
* #used metadata blocks : Number of metadata blocks used
|
||||
* #total metadata blocks : Total number of metadata blocks
|
||||
* cache block size : Configurable block size for the cache device
|
||||
* in sectors
|
||||
* #used cache blocks : Number of blocks resident in the cache
|
||||
* #total cache blocks : Total number of cache blocks
|
||||
* #read hits : Number of times a READ bio has been mapped
|
||||
* to the cache
|
||||
* #read misses : Number of times a READ bio has been mapped
|
||||
* to the origin
|
||||
* #write hits : Number of times a WRITE bio has been mapped
|
||||
* to the cache
|
||||
* #write misses : Number of times a WRITE bio has been
|
||||
* mapped to the origin
|
||||
* #demotions : Number of times a block has been removed
|
||||
* from the cache
|
||||
* #promotions : Number of times a block has been moved to
|
||||
* the cache
|
||||
* #dirty : Number of blocks in the cache that differ
|
||||
* from the origin
|
||||
* #feature args : Number of feature args to follow
|
||||
* feature args : 'writethrough' (optional)
|
||||
* #core args : Number of core arguments (must be even)
|
||||
* core args : Key/value pairs for tuning the core
|
||||
* e.g. migration_threshold
|
||||
* *policy name : Name of the policy
|
||||
* #policy args : Number of policy arguments to follow (must be even)
|
||||
* policy args : Key/value pairs
|
||||
* e.g. sequential_threshold
|
||||
*/
|
||||
int dm_get_status_cache(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_cache **status)
|
||||
{
|
||||
int i, feature_argc;
|
||||
char *str;
|
||||
const char *p, *pp;
|
||||
struct dm_status_cache *s;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_cache))))
|
||||
return_0;
|
||||
|
||||
/* Read in args that have definitive placement */
|
||||
if (sscanf(params,
|
||||
" %" PRIu32
|
||||
" %" PRIu64 "/%" PRIu64
|
||||
" %" PRIu32
|
||||
" %" PRIu64 "/%" PRIu64
|
||||
" %" PRIu64 " %" PRIu64
|
||||
" %" PRIu64 " %" PRIu64
|
||||
" %" PRIu64 " %" PRIu64
|
||||
" %" PRIu64
|
||||
" %d",
|
||||
&s->metadata_block_size,
|
||||
&s->metadata_used_blocks, &s->metadata_total_blocks,
|
||||
&s->block_size, /* AKA, chunk_size */
|
||||
&s->used_blocks, &s->total_blocks,
|
||||
&s->read_hits, &s->read_misses,
|
||||
&s->write_hits, &s->write_misses,
|
||||
&s->demotions, &s->promotions,
|
||||
&s->dirty_blocks,
|
||||
&feature_argc) != 14)
|
||||
goto bad;
|
||||
|
||||
/* Now jump to "features" section */
|
||||
if (!(p = _advance_to_next_word(params, 12)))
|
||||
goto bad;
|
||||
|
||||
/* Read in features */
|
||||
for (i = 0; i < feature_argc; i++) {
|
||||
if (!strncmp(p, "writethrough ", 13))
|
||||
s->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
|
||||
else if (!strncmp(p, "writeback ", 10))
|
||||
s->feature_flags |= DM_CACHE_FEATURE_WRITEBACK;
|
||||
else
|
||||
log_error("Unknown feature in status: %s", params);
|
||||
|
||||
if (!(p = _advance_to_next_word(p, 1)))
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Read in core_args. */
|
||||
if (sscanf(p, "%d ", &s->core_argc) != 1)
|
||||
goto bad;
|
||||
if (s->core_argc &&
|
||||
(!(s->core_argv = dm_pool_zalloc(mem, sizeof(char *) * s->core_argc)) ||
|
||||
!(p = _advance_to_next_word(p, 1)) ||
|
||||
!(str = dm_pool_strdup(mem, p)) ||
|
||||
!(p = _advance_to_next_word(p, s->core_argc)) ||
|
||||
(dm_split_words(str, s->core_argc, 0, s->core_argv) != s->core_argc)))
|
||||
goto bad;
|
||||
|
||||
/* Read in policy args */
|
||||
pp = p;
|
||||
if (!(p = _advance_to_next_word(p, 1)) ||
|
||||
!(s->policy_name = dm_pool_zalloc(mem, (p - pp))))
|
||||
goto bad;
|
||||
if (sscanf(pp, "%s %d", s->policy_name, &s->policy_argc) != 2)
|
||||
goto bad;
|
||||
if (s->policy_argc &&
|
||||
(!(s->policy_argv = dm_pool_zalloc(mem, sizeof(char *) * s->policy_argc)) ||
|
||||
!(p = _advance_to_next_word(p, 1)) ||
|
||||
!(str = dm_pool_strdup(mem, p)) ||
|
||||
(dm_split_words(str, s->policy_argc, 0, s->policy_argv) != s->policy_argc)))
|
||||
goto bad;
|
||||
|
||||
*status = s;
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
log_error("Failed to parse cache params: %s", params);
|
||||
dm_pool_free(mem, s);
|
||||
*status = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_thin_pool_status(const char *params, struct dm_status_thin_pool *s)
|
||||
{
|
||||
int pos;
|
||||
|
||||
if (!params) {
|
||||
log_error("Failed to parse invalid thin params.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: add support for held metadata root */
|
||||
if (sscanf(params, FMTu64 " " FMTu64 "/" FMTu64 " " FMTu64 "/" FMTu64 "%n",
|
||||
&s->transaction_id,
|
||||
&s->used_metadata_blocks,
|
||||
&s->total_metadata_blocks,
|
||||
&s->used_data_blocks,
|
||||
&s->total_data_blocks, &pos) < 5) {
|
||||
log_error("Failed to parse thin pool params: %s.", params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* New status flags */
|
||||
if (strstr(params + pos, "no_discard_passdown"))
|
||||
s->discards = DM_THIN_DISCARDS_NO_PASSDOWN;
|
||||
else if (strstr(params + pos, "ignore_discard"))
|
||||
s->discards = DM_THIN_DISCARDS_IGNORE;
|
||||
else /* default discard_passdown */
|
||||
s->discards = DM_THIN_DISCARDS_PASSDOWN;
|
||||
|
||||
if (strstr(params + pos, "ro "))
|
||||
s->read_only = 1;
|
||||
else if (strstr(params + pos, "fail"))
|
||||
s->fail = 1;
|
||||
else if (strstr(params + pos, "out_of_data_space"))
|
||||
s->out_of_data_space = 1;
|
||||
|
||||
if (strstr(params + pos, "error_if_no_space"))
|
||||
s->error_if_no_space = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_get_status_thin_pool(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_thin_pool **status)
|
||||
{
|
||||
struct dm_status_thin_pool *s;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_thin_pool)))) {
|
||||
log_error("Failed to allocate thin_pool status structure.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!parse_thin_pool_status(params, s)) {
|
||||
dm_pool_free(mem, s);
|
||||
return_0;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_get_status_thin(struct dm_pool *mem, const char *params,
|
||||
struct dm_status_thin **status)
|
||||
{
|
||||
struct dm_status_thin *s;
|
||||
|
||||
if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_thin)))) {
|
||||
log_error("Failed to allocate thin status structure.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strchr(params, '-')) {
|
||||
s->mapped_sectors = 0;
|
||||
s->highest_mapped_sector = 0;
|
||||
} else if (sscanf(params, FMTu64 " " FMTu64,
|
||||
&s->mapped_sectors,
|
||||
&s->highest_mapped_sector) != 2) {
|
||||
dm_pool_free(mem, s);
|
||||
log_error("Failed to parse thin params: %s.", params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*status = s;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -56,7 +56,7 @@ const char *lvm_lv_get_uuid(const lv_t lv)
|
||||
{
|
||||
const char *rc;
|
||||
struct saved_env e = store_user_env(lv->vg->cmd);
|
||||
rc = lv_uuid_dup(lv);
|
||||
rc = lv_uuid_dup(lv->vg->vgmem, lv);
|
||||
restore_user_env(&e);
|
||||
return rc;
|
||||
}
|
||||
@@ -205,7 +205,7 @@ static void _lv_set_default_params(struct lvcreate_params *lp,
|
||||
}
|
||||
|
||||
static struct segment_type * _get_segtype(struct cmd_context *cmd) {
|
||||
struct segment_type *rc = get_segtype_from_string(cmd, "striped");
|
||||
struct segment_type *rc = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED);
|
||||
if (!rc) {
|
||||
log_error(INTERNAL_ERROR "Segtype striped not found.");
|
||||
}
|
||||
@@ -503,7 +503,7 @@ static int _lv_set_pool_params(struct lvcreate_params *lp,
|
||||
_lv_set_default_params(lp, vg, pool_name, extents);
|
||||
|
||||
lp->create_pool = 1;
|
||||
lp->segtype = get_segtype_from_string(vg->cmd, "thin-pool");
|
||||
lp->segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_THIN_POOL);
|
||||
lp->stripes = 1;
|
||||
|
||||
if (!meta_size) {
|
||||
@@ -611,7 +611,7 @@ static int _lv_set_thin_params(struct lvcreate_params *lp,
|
||||
_lv_set_default_params(lp, vg, lvname, 0);
|
||||
|
||||
lp->pool_name = pool_name;
|
||||
lp->segtype = get_segtype_from_string(vg->cmd, "thin");
|
||||
lp->segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_THIN);
|
||||
lp->virtual_extents = extents;
|
||||
lp->stripes = 1;
|
||||
|
||||
@@ -655,14 +655,14 @@ static lv_create_params_t _lvm_lv_params_create_snapshot(const lv_t lv,
|
||||
_lv_set_default_params(&lvcp->lvp, lv->vg, snap_name, extents);
|
||||
|
||||
if (size) {
|
||||
if (!(lvcp->lvp.segtype = get_segtype_from_string(lv->vg->cmd, "snapshot"))) {
|
||||
if (!(lvcp->lvp.segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_SNAPSHOT))) {
|
||||
log_error("Segtype snapshot not found.");
|
||||
return NULL;
|
||||
}
|
||||
lvcp->lvp.chunk_size = 8;
|
||||
lvcp->lvp.snapshot = 1;
|
||||
} else {
|
||||
if (!(lvcp->lvp.segtype = get_segtype_from_string(lv->vg->cmd, "thin"))) {
|
||||
if (!(lvcp->lvp.segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_THIN))) {
|
||||
log_error("Segtype thin not found.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ const char *lvm_pv_get_uuid(const pv_t pv)
|
||||
{
|
||||
const char *rc;
|
||||
struct saved_env e = store_user_env(pv->vg->cmd);
|
||||
rc = pv_uuid_dup(pv);
|
||||
rc = pv_uuid_dup(pv->vg->vgmem, pv);
|
||||
restore_user_env(&e);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -497,7 +497,9 @@ EXPORTED_SYMBOLS := $(wildcard $(srcdir)/.exported_symbols.Base $(srcdir)/.expor
|
||||
ifeq (,$(firstword $(EXPORTED_SYMBOLS)))
|
||||
set -e; (echo "Base {"; echo " global:";\
|
||||
$(SED) "s/^/ /;s/$$/;/" $<;\
|
||||
echo " local:"; echo " *;"; echo "};") > $@
|
||||
echo "};";\
|
||||
echo "Local {"; echo " local:"; echo " *;"; echo "};";\
|
||||
) > $@
|
||||
else
|
||||
set -e;\
|
||||
R=$$(sort $^ | uniq -u);\
|
||||
|
||||
@@ -14,10 +14,11 @@ blkdeactivate \(em utility to deactivate block devices
|
||||
blkdeactivate utility deactivates block devices. If a device
|
||||
is mounted, the utility can unmount it automatically before
|
||||
trying to deactivate. The utility currently supports
|
||||
device-mapper devices, including LVM volumes.
|
||||
LVM volumes are handled directly using the \fBlvm\fP(8) command.
|
||||
Other device-mapper based devices are handled using the
|
||||
\fBdmsetup\fP(8) command.
|
||||
device-mapper devices (DM), including LVM volumes and
|
||||
software RAID MD devices. LVM volumes are handled directly
|
||||
using the \fBlvm\fP(8) command, the rest of device-mapper
|
||||
based devices are handled using the \fBdmsetup\fP(8) command.
|
||||
MD devices are handled using the \fBmdadm\fP(8) command.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-d ", " \-\-dmoption \ \fIdm_options\fP
|
||||
@@ -88,4 +89,5 @@ of device-mapper devices in case the deactivation fails and force removal.
|
||||
.BR dmsetup (8),
|
||||
.BR lsblk (8),
|
||||
.BR lvm (8),
|
||||
.BR mdadm (8),
|
||||
.BR umount (8)
|
||||
|
||||
160
man/clvmd.8.in
160
man/clvmd.8.in
@@ -1,130 +1,172 @@
|
||||
.TH CLVMD 8 "LVM TOOLS #VERSION#" "Red Hat Inc" \" -*- nroff -*-
|
||||
.
|
||||
.SH NAME
|
||||
.
|
||||
clvmd \(em cluster LVM daemon
|
||||
.
|
||||
.SH SYNOPSIS
|
||||
.
|
||||
.ad l
|
||||
.B clvmd
|
||||
.RB [ \-C ]
|
||||
.RB [ \-d [< \fIvalue\fP >]]
|
||||
.RB [ \-d
|
||||
.RI [ value ]]
|
||||
.RB [ \-E
|
||||
.RI < "lock uuid" >]
|
||||
.IR lock_uuid ]
|
||||
.RB [ \-f ]
|
||||
.RB [ \-h ]
|
||||
.RB [ \-I
|
||||
.IR "cluster_manager" ]
|
||||
.IR cluster_manager ]
|
||||
.RB [ \-R ]
|
||||
.RB [ \-S ]
|
||||
.RB [ \-t
|
||||
.RI < timeout >]
|
||||
.IR timeout ]
|
||||
.RB [ \-T
|
||||
.RI < "start timeout" >]
|
||||
.IR start_timeout ]
|
||||
.RB [ \-V ]
|
||||
.ad b
|
||||
.
|
||||
.SH DESCRIPTION
|
||||
.
|
||||
clvmd is the daemon that distributes LVM metadata updates around a cluster.
|
||||
It must be running on all nodes in the cluster and will give an error
|
||||
if a node in the cluster does not have this daemon running.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-d [< \fIvalue >]
|
||||
Set debug logging level.If \fB\-d\fP is specified without a \fIvalue\fP
|
||||
then 1 is assumed. \fIValue\fP can be:
|
||||
.RS
|
||||
.IP \fI0\fP
|
||||
Disabled
|
||||
.IP \fI1\fP
|
||||
Sends debug logs to stderr (implies \fB\-f\fP)
|
||||
.IP \fI2\fP
|
||||
Sends debug logs to \fBsyslog\fP(3)
|
||||
.RE
|
||||
.TP
|
||||
.B \-C
|
||||
Only valid if
|
||||
.B \-d
|
||||
is also specified. Tells all clvmds in a cluster to enable/disable debug logging.
|
||||
Without this switch, only the local clvmd will change its debug level to that
|
||||
given with
|
||||
.B \-d
|
||||
.
|
||||
.SH OPTIONS
|
||||
.
|
||||
.HP
|
||||
.BR \-C
|
||||
.br
|
||||
Only valid if \fB\-d\fP is also specified.
|
||||
Tells all clvmds in a cluster to enable/disable debug logging.
|
||||
Without this switch, only the local clvmd will change its debug level to that
|
||||
given with \fB\-d\fP.
|
||||
.br
|
||||
This does not work correctly if specified on the command-line that starts clvmd.
|
||||
If you want to start clvmd
|
||||
.B and
|
||||
If you want to start clvmd \fBand\fP
|
||||
enable cluster-wide logging then the command needs to be issued twice, eg:
|
||||
.br
|
||||
.B clvmd
|
||||
.BR clvmd
|
||||
.br
|
||||
.B clvmd \-d2
|
||||
.BR clvmd\ \-d2
|
||||
.
|
||||
.HP
|
||||
.BR \-d
|
||||
.RI [ value ]
|
||||
.br
|
||||
Set debug logging level.
|
||||
If \fB\-d\fP is specified without a \fIvalue\fP
|
||||
then 1 is assumed. \fIValue\fP can be:
|
||||
.PD 0
|
||||
.IP
|
||||
.BR 0
|
||||
\(em Disabled
|
||||
.IP
|
||||
.BR 1
|
||||
\(em Sends debug logs to stderr (implies \fB\-f\fP)
|
||||
.IP
|
||||
.BR 2
|
||||
\(em Sends debug logs to \fBsyslog\fP(3)
|
||||
.PD
|
||||
.
|
||||
.HP
|
||||
.BR \-E
|
||||
.IR lock_uuid
|
||||
.br
|
||||
.TP
|
||||
.BR \-E < "\fIlock uuid" >
|
||||
Pass lock uuid to be reacquired exclusively when clvmd is restarted.
|
||||
.TP
|
||||
.B \-f
|
||||
.
|
||||
.HP
|
||||
.BR \-f
|
||||
.br
|
||||
Don't fork, run in the foreground.
|
||||
.TP
|
||||
.B \-h
|
||||
.
|
||||
.HP
|
||||
.BR \-h
|
||||
.br
|
||||
Show help information.
|
||||
.TP
|
||||
.BR \-I " \fIcluster_manager\fP"
|
||||
Selects the \fIcluster manager\fP to use for locking and internal
|
||||
.
|
||||
.HP
|
||||
.BR \-I
|
||||
.IR cluster_manager
|
||||
.br
|
||||
Selects the cluster manager to use for locking and internal
|
||||
communications. As it is quite possible to have multiple managers available on
|
||||
the same system you might have to manually specify this option to override the
|
||||
search.
|
||||
|
||||
By default, omit \fB-I\fP is equivalent to \fB\-I\fP\fIauto\fP. \fBClvmd\fP
|
||||
will use the first cluster manager that succeeds, and it checks them in a
|
||||
predefined order cman,corosync,openais.
|
||||
By default, omit \fB-I\fP is equivalent to \fB\-Iauto\fP.
|
||||
Clvmd will use the first cluster manager that succeeds,
|
||||
and it checks them in a predefined order
|
||||
.BR cman ,
|
||||
.BR corosync ,
|
||||
.BR openais .
|
||||
The available managers will be listed by order as part of the
|
||||
\fBclvmd \-h\fP output.
|
||||
.TP
|
||||
.B \-R
|
||||
.
|
||||
.HP
|
||||
.BR \-R
|
||||
.br
|
||||
Tells all the running instance of \fBclvmd\fP in the cluster to reload their device cache and
|
||||
re-read the lvm configuration file \fBlvm.conf\fP(5). This command should be run whenever the
|
||||
devices on a cluster system are changed.
|
||||
.TP
|
||||
.B \-S
|
||||
.
|
||||
.HP
|
||||
.BR \-S
|
||||
.br
|
||||
Tells the running \fBclvmd\fP to exit and reexecute itself, for example at the
|
||||
end of a package upgrade. The new instance is instructed to reacquire
|
||||
any locks in the same state as they were previously held. (Alternative
|
||||
methods of restarting the daemon have the side effect of changing
|
||||
exclusive LV locks into shared locks.)
|
||||
.TP
|
||||
.BR \-t < \fItimeout >
|
||||
.
|
||||
.HP
|
||||
.BR \-t
|
||||
.IR timeout
|
||||
.br
|
||||
Specifies the \fItimeout\fP for commands to run around the cluster. This should not
|
||||
be so small that commands with many disk updates to do will fail, so you
|
||||
may need to increase this on systems with very large disk farms.
|
||||
The default is 60 seconds.
|
||||
.TP
|
||||
.BR \-T < "\fIstart timeout" >
|
||||
Specifies the \fIstart timeout\fP for \fBclvmd\fP daemon startup. If the
|
||||
.
|
||||
.HP
|
||||
.BR \-T
|
||||
.IR start_timeout
|
||||
.br
|
||||
Specifies the start timeout for \fBclvmd\fP daemon startup. If the
|
||||
daemon does not report that it has started up within this time then the parent
|
||||
command will exit with status of 5. This does NOT mean that \fBclvmd\fP has
|
||||
not started! What it means is that the startup has been delayed for some
|
||||
reason; the most likely cause of this is an inquorate cluster though it
|
||||
could be due to locking latencies on a cluster with large numbers of logical
|
||||
volumes. If you get the return code of 5 it is usually not necessary to
|
||||
restart \fBclvmd\fP — it will start as soon as that blockage has cleared.
|
||||
restart \fBclvmd\fP it will start as soon as that blockage has cleared.
|
||||
This flag is to allow startup scripts to exit in a timely fashion even if the
|
||||
cluster is stalled for some reason.
|
||||
|
||||
The default is 0 (no timeout) and the value is in seconds. Don't set this too
|
||||
The default is \fB0\fP (no timeout) and the value is in seconds. Don't set this too
|
||||
small or you will experience spurious errors. 10 or 20 seconds might be
|
||||
sensible.
|
||||
|
||||
This timeout will be ignored if you start \fBclvmd\fP with the \fB\-d\fP.
|
||||
.TP
|
||||
.B \-V
|
||||
.
|
||||
.HP
|
||||
.BR \-V
|
||||
.br
|
||||
Display the version of the cluster LVM daemon.
|
||||
|
||||
.
|
||||
.SH ENVIRONMENT VARIABLES
|
||||
.TP
|
||||
.B LVM_CLVMD_BINARY
|
||||
The CLVMD binary to use when \fBclvmd\fP restart is requested.
|
||||
Defaults to #CLVMD_PATH#.
|
||||
Defaults to \fI#CLVMD_PATH#\fP.
|
||||
.TP
|
||||
.B LVM_BINARY
|
||||
The LVM2 binary to use.
|
||||
Defaults to #LVM_PATH#.
|
||||
|
||||
Defaults to \fI#LVM_PATH#\fP.
|
||||
.SH FILES
|
||||
.I #CLVMD_PATH#
|
||||
.br
|
||||
.I #LVM_PATH#
|
||||
.SH SEE ALSO
|
||||
.BR syslog (3),
|
||||
.BR lvm.conf (5),
|
||||
|
||||
@@ -1,43 +1,68 @@
|
||||
.TH DMEVENTD 8 "DM TOOLS #VERSION#" "Red Hat Inc" \" -*- nroff -*-
|
||||
.
|
||||
.SH NAME
|
||||
.
|
||||
dmeventd \(em Device-mapper event daemon
|
||||
.
|
||||
.SH SYNOPSIS
|
||||
.
|
||||
.B dmeventd
|
||||
.RB [ \-d
|
||||
.RB [ \-d
|
||||
.RB [ \-d ]]]
|
||||
.RB [ \-f ]
|
||||
.RB [ \-h ]
|
||||
.RB [ \-l ]
|
||||
.RB [ \-R ]
|
||||
.RB [ \-V ]
|
||||
.RB [ \-? ]
|
||||
.
|
||||
.SH DESCRIPTION
|
||||
.
|
||||
dmeventd is the event monitoring daemon for device-mapper devices.
|
||||
Library plugins can register and carry out actions triggered when
|
||||
particular events occur.
|
||||
.SH
|
||||
LVM PLUGINS
|
||||
.TP
|
||||
.I Mirror
|
||||
Attempts to handle device failure automatically. See \fBlvm.conf\fP(5).
|
||||
.TP
|
||||
.I Raid
|
||||
Attempts to handle device failure automatically. See \fBlvm.conf\fP(5).
|
||||
.TP
|
||||
.I Snapshot
|
||||
.
|
||||
.SH LVM PLUGINS
|
||||
.
|
||||
.HP
|
||||
.IR Mirror
|
||||
.br
|
||||
Attempts to handle device failure automatically. See
|
||||
.BR lvm.conf (5).
|
||||
.
|
||||
.HP
|
||||
.IR Raid
|
||||
.br
|
||||
Attempts to handle device failure automatically. See
|
||||
.BR lvm.conf (5).
|
||||
.
|
||||
.HP
|
||||
.IR Snapshot
|
||||
.br
|
||||
Monitors how full a snapshot is becoming and emits a warning to
|
||||
syslog when it exceeds 80% full.
|
||||
The warning is repeated when 85%, 90% and 95% of the snapshot is filled.
|
||||
See \fBlvm.conf\fP(5).
|
||||
.TP
|
||||
.I Thin
|
||||
Monitors how full a thin pool is becoming and emits a warning to
|
||||
syslog when it exceeds 80% full.
|
||||
See
|
||||
.BR lvm.conf (5).
|
||||
Snapshot which runs out of space gets invalid and when it is mounted,
|
||||
it gets umounted if possible.
|
||||
.
|
||||
.HP
|
||||
.IR Thin
|
||||
.br
|
||||
Monitors how full a thin pool data and metadata is becoming and emits
|
||||
a warning to syslog when it exceeds 80% full.
|
||||
The warning is repeated when 85%, 90% and 95% of the thin pool is filled.
|
||||
See \fBlvm.conf\fP(5).
|
||||
See
|
||||
.BR lvm.conf (5).
|
||||
If the thin-pool runs out of space, thin volumes are umounted if possible.
|
||||
.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-d
|
||||
.
|
||||
.HP
|
||||
.BR \-d
|
||||
.br
|
||||
Repeat from 1 to 3 times (
|
||||
.BR \-d ,
|
||||
.BR \-dd ,
|
||||
@@ -45,21 +70,41 @@ Repeat from 1 to 3 times (
|
||||
) to increase the detail of
|
||||
debug messages sent to syslog.
|
||||
Each extra d adds more debugging information.
|
||||
.TP
|
||||
.B \-f
|
||||
.
|
||||
.HP
|
||||
.BR \-f
|
||||
.br
|
||||
Don't fork, run in the foreground.
|
||||
.TP
|
||||
.BR \-h ", " \-?
|
||||
.
|
||||
.HP
|
||||
.BR \-h
|
||||
.br
|
||||
Show help information.
|
||||
.TP
|
||||
.B \-R
|
||||
.
|
||||
.HP
|
||||
.BR \-l
|
||||
.br
|
||||
Log through stdout and stderr instead of syslog.
|
||||
This option works only with option \-f, otherwise it is ignored.
|
||||
.
|
||||
.HP
|
||||
.BR \-?
|
||||
.br
|
||||
Show help information on stderr.
|
||||
.
|
||||
.HP
|
||||
.BR \-R
|
||||
.br
|
||||
Replace a running dmeventd instance. The running dmeventd must be version
|
||||
2.02.77 or newer. The new dmeventd instance will obtain a list of devices and
|
||||
events to monitor from the currently running daemon.
|
||||
.TP
|
||||
.B \-V
|
||||
.
|
||||
.HP
|
||||
.BR \-V
|
||||
.br
|
||||
Show version of dmeventd.
|
||||
|
||||
.
|
||||
.SH SEE ALSO
|
||||
.
|
||||
.BR lvm (8),
|
||||
.BR lvm.conf (5)
|
||||
|
||||
1175
man/dmsetup.8.in
1175
man/dmsetup.8.in
File diff suppressed because it is too large
Load Diff
918
man/dmstats.8.in
918
man/dmstats.8.in
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user