mirror of
git://sourceware.org/git/lvm2.git
synced 2025-12-25 20:23:49 +03:00
Compare commits
133 Commits
dm_v1_02_1
...
dm_v1_02_1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e366b68ad3 | ||
|
|
fb94fb980a | ||
|
|
b10cc18f53 | ||
|
|
a249de3b72 | ||
|
|
d04e972d65 | ||
|
|
b9f5a18a76 | ||
|
|
d3f157f08a | ||
|
|
2294fdb496 | ||
|
|
d7ba0e01a5 | ||
|
|
b6172b53fd | ||
|
|
477ec611d5 | ||
|
|
b6194edd67 | ||
|
|
dcdbbb3ecb | ||
|
|
7ef99ee4e6 | ||
|
|
1ac1418286 | ||
|
|
8fc854f38e | ||
|
|
1c2360b335 | ||
|
|
dd4477406b | ||
|
|
9d67bbb104 | ||
|
|
d6c8e1df61 | ||
|
|
5ec7c8fece | ||
|
|
86b21eaf83 | ||
|
|
228486a971 | ||
|
|
88c0caab26 | ||
|
|
5cd4679419 | ||
|
|
eeed5e0d19 | ||
|
|
369ab1e0b2 | ||
|
|
2e21519a10 | ||
|
|
ecc001ed08 | ||
|
|
cd96852696 | ||
|
|
b9f7f30158 | ||
|
|
ca5e423331 | ||
|
|
fa9407089c | ||
|
|
66f28e193a | ||
|
|
0d93f89f5c | ||
|
|
154e9a2c47 | ||
|
|
84574a1257 | ||
|
|
bf83527b64 | ||
|
|
12c53622a0 | ||
|
|
d8f54cf891 | ||
|
|
625a671189 | ||
|
|
6ebdad3102 | ||
|
|
9a8f21aa03 | ||
|
|
291dd8edc2 | ||
|
|
de4c1daf29 | ||
|
|
0b55d7d0d8 | ||
|
|
5d86fd8fdb | ||
|
|
1b76eb1f59 | ||
|
|
b05678d8bf | ||
|
|
781f4971c6 | ||
|
|
d02ac7b99a | ||
|
|
b1b6c97f7c | ||
|
|
baee28ab5c | ||
|
|
83edf68ff9 | ||
|
|
c7588f91dd | ||
|
|
30b432adc5 | ||
|
|
7c9733eb5d | ||
|
|
a223c3fea3 | ||
|
|
d5250f4901 | ||
|
|
25f29f4712 | ||
|
|
382af5563d | ||
|
|
8cf3d165d3 | ||
|
|
0fd6ce546f | ||
|
|
b881c372bc | ||
|
|
94c5e7deb0 | ||
|
|
c344766f3c | ||
|
|
67895de0bc | ||
|
|
ff00cb6990 | ||
|
|
2cc75c11ed | ||
|
|
cd79e58eda | ||
|
|
6fa801f3d8 | ||
|
|
684eecba1d | ||
|
|
da9cf7e5de | ||
|
|
f57e7445fd | ||
|
|
fba1388719 | ||
|
|
80ed029c17 | ||
|
|
34a74e81e3 | ||
|
|
cb120ddb15 | ||
|
|
f9ee4395b0 | ||
|
|
71f06d51ed | ||
|
|
217f70952f | ||
|
|
f813d41a76 | ||
|
|
d851289d8a | ||
|
|
b115b8a2ea | ||
|
|
d0f7067471 | ||
|
|
be5b4c38a7 | ||
|
|
d6d597e3dd | ||
|
|
84e348fade | ||
|
|
910054657e | ||
|
|
8357a11249 | ||
|
|
9b021ba057 | ||
|
|
317e588efd | ||
|
|
b1d32a03c7 | ||
|
|
ee6e6529ee | ||
|
|
9d944d6cf9 | ||
|
|
13635d281a | ||
|
|
2493c46970 | ||
|
|
63e4217271 | ||
|
|
f4bd12e8e9 | ||
|
|
df15f46900 | ||
|
|
fb3a732361 | ||
|
|
2d74110feb | ||
|
|
19d102082d | ||
|
|
d2af2c9487 | ||
|
|
82980149fa | ||
|
|
a19bb7b909 | ||
|
|
9d98c3278d | ||
|
|
26376ac1c9 | ||
|
|
8459f99341 | ||
|
|
e5bdb0e0b5 | ||
|
|
1106b7775a | ||
|
|
ae2852156d | ||
|
|
44c6c36c43 | ||
|
|
a81926503d | ||
|
|
af13ccddda | ||
|
|
392e1bc2e8 | ||
|
|
9268d92c70 | ||
|
|
bb3366c07d | ||
|
|
d24d563ebc | ||
|
|
954bd9257b | ||
|
|
5d51a56c02 | ||
|
|
f48648552e | ||
|
|
edb9c3cc9f | ||
|
|
01dc83b936 | ||
|
|
3a8dff3a62 | ||
|
|
13b234ccba | ||
|
|
e451e93664 | ||
|
|
b4f9531475 | ||
|
|
3184ff75c4 | ||
|
|
43243f4d30 | ||
|
|
c975a100b1 | ||
|
|
02bf389425 | ||
|
|
bcb9a3dd04 |
96
WHATS_NEW
96
WHATS_NEW
@@ -1,3 +1,99 @@
|
||||
Version 2.02.25 - 27th April 2007
|
||||
=================================
|
||||
Fix get_config_uint64() to read a 64-bit value not a 32-bit one.
|
||||
Add -Wformat-security and change one fprintf() to fputs().
|
||||
Move regex functions into libdevmapper.
|
||||
Change some #include lines to search only standard system directories.
|
||||
Add devices/preferred_names config regex list for displayed device names.
|
||||
Free a temporary dir string in fcntl_lock_file() after use.
|
||||
Fix a dm_pool_destroy() in matcher_create().
|
||||
Introduce goto_bad macro.
|
||||
Fix warnings on x86_64 involving ptrdiff_t in log_error messages.
|
||||
Update pvck to include text metadata area and record detection.
|
||||
Add support functions for token counting in config file extracts.
|
||||
Update pvck to read labels on disk, with --labelsector parameter.
|
||||
Add count_chars and count_chars_len functions.
|
||||
Add /sys/block listings to lvm_dump.sh.
|
||||
Make lvm_dump.sh list /dev recursively.
|
||||
Fix thread race in clvmd.
|
||||
Add scan_sector param to label_read and _find_labeller.
|
||||
Make clvmd cope with quorum devices.
|
||||
Add extra internal error checking to clvmd.
|
||||
Add dev_read_circular.
|
||||
Add pvck command stub.
|
||||
Update lists of attribute characters in man pages.
|
||||
Change cling alloc policy attribute character from 'C' to l'.
|
||||
Fix creation and conversion of mirrors with tags.
|
||||
Fix vgsplit for lvm1 format (set and validate VG name in PVs metadata).
|
||||
Split metadata areas in vgsplit properly.
|
||||
|
||||
Version 2.02.24 - 19th March 2007
|
||||
=================================
|
||||
Fix processing of exit status in init scripts
|
||||
Fix vgremove to require at least one vg argument.
|
||||
Fix reading of striped LVs in LVM1 format.
|
||||
Flag nolocking as clustered so clvmd startup sees clustered LVs. (2.02.10)
|
||||
Add a few missing pieces of vgname command line validation.
|
||||
Support the /dev/mapper prefix on most command lines.
|
||||
|
||||
Version 2.02.23 - 8th March 2007
|
||||
================================
|
||||
Fix vgrename active LV check to ignore differing vgids.
|
||||
Remove no-longer-used uuid_out parameter from activation info functions.
|
||||
Fix two more segfaults if an empty config file section encountered.
|
||||
Move .cache file into a new /etc/lvm/cache directory by default.
|
||||
Add devices/cache_dir & devices/cache_file_prefix, deprecating devices/cache.
|
||||
Create directory in fcntl_lock_file() if required.
|
||||
Exclude readline support from lvm.static.
|
||||
Fix a leak in a reporting error path (2.02.19).
|
||||
|
||||
Version 2.02.22 - 13th February 2007
|
||||
====================================
|
||||
Correct -b and -P on a couple of man pages.
|
||||
Add global/units to example.conf.
|
||||
Fix loading of segment_libraries.
|
||||
If a PV reappears after it was removed from its VG, make it an orphan.
|
||||
Don't update metadata automatically if VGIDs don't match.
|
||||
Fix some vgreduce --removemissing command line validation.
|
||||
|
||||
Version 2.02.21 - 30th January 2007
|
||||
===================================
|
||||
Add warning to lvm2_monitoring_init_rhel4 if attempting to stop monitoring.
|
||||
Fix vgsplit to handle mirrors.
|
||||
Reorder fields in reporting field definitions.
|
||||
Fix vgs to treat args as VGs even when PV fields are displayed.
|
||||
Fix md signature check to handle both endiannesses.
|
||||
|
||||
Version 2.02.20 - 25th January 2007
|
||||
===================================
|
||||
dmeventd mirror sets ignore_suspended_devices and avoids scanning mirrors.
|
||||
Add devices/ignore_suspended_devices to ignore suspended dm devices.
|
||||
Add some missing close() and fclose() return code checks.
|
||||
Fix exit statuses of reporting tools (2.02.19).
|
||||
Add init script for dmeventd monitoring.
|
||||
lvm.static no longer interacts with dmeventd unless explicitly asked to.
|
||||
Add field definitions to report help text.
|
||||
Remove unnecessary cmd arg from target_*monitor_events().
|
||||
Add private variable to dmeventd shared library interface.
|
||||
Long-lived processes write out persistent dev cache in refresh_toolcontext().
|
||||
Fix refresh_toolcontext() always to wipe persistent device filter cache.
|
||||
Add is_long_lived to toolcontext.
|
||||
Add --clustered to man pages.
|
||||
Streamline dm_report_field_* interface.
|
||||
Change remaining dmeventd terminology 'register' to 'monitor'.
|
||||
Update reporting man pages.
|
||||
No longer necessary to specify alignment type for report fields.
|
||||
|
||||
Version 2.02.19 - 17th January 2007
|
||||
===================================
|
||||
Fix a segfault if an empty config file section encountered.
|
||||
Move basic reporting functions into libdevmapper.
|
||||
Fix partition table processing after sparc changes (2.02.16).
|
||||
Fix cmdline PE range processing segfault (2.02.13).
|
||||
Some libdevmapper-event interface changes.
|
||||
Report dmeventd mirror monitoring status.
|
||||
Fix dmeventd mirror status line processing.
|
||||
|
||||
Version 2.02.18 - 11th January 2007
|
||||
===================================
|
||||
Revised libdevmapper-event interface for dmeventd.
|
||||
|
||||
46
WHATS_NEW_DM
46
WHATS_NEW_DM
@@ -1,3 +1,49 @@
|
||||
Version 1.02.19 - 27th April 2007
|
||||
=================================
|
||||
Standardise protective include file #defines.
|
||||
Add regex functions to library.
|
||||
Avoid trailing separator in reports when there are hidden sort fields.
|
||||
Fix segfault in 'dmsetup status' without --showkeys against crypt target.
|
||||
Deal with some more compiler warnings.
|
||||
Introduce _add_field() and _is_same_field() to libdm-report.c.
|
||||
Fix some libdevmapper-event and dmeventd memory leaks.
|
||||
Remove unnecessary memset() return value checks.
|
||||
Fix a few leaks in reporting error paths. [1.02.15+]
|
||||
|
||||
Version 1.02.18 - 13th February 2007
|
||||
====================================
|
||||
Improve dmeventd messaging protocol: drain pipe and tag messages.
|
||||
|
||||
Version 1.02.17 - 29th January 2007
|
||||
===================================
|
||||
Add recent reporting options to dmsetup man page.
|
||||
Revise some report fields names.
|
||||
Add dmsetup 'help' command and update usage text.
|
||||
Use fixed-size fields in report interface and reorder.
|
||||
|
||||
Version 1.02.16 - 25th January 2007
|
||||
===================================
|
||||
Add some missing close() and fclose() return value checks.
|
||||
Migrate dmsetup column-based output over to new libdevmapper report framework.
|
||||
Add descriptions to reporting field definitions.
|
||||
Add a dso-private variable to dmeventd dso interface.
|
||||
Add dm_event_handler_[gs]et_timeout functions.
|
||||
Streamline dm_report_field_* interface.
|
||||
Add cmdline debug & version options to dmeventd.
|
||||
Add DM_LIB_VERSION definition to configure.h.
|
||||
Suppress 'Unrecognised field' error if report field is 'help'.
|
||||
Add --separator and --sort to dmsetup (unused).
|
||||
Make alignment flag optional when specifying report fields.
|
||||
|
||||
Version 1.02.15 - 17th January 2007
|
||||
===================================
|
||||
Add basic reporting functions to libdevmapper.
|
||||
Fix a malloc error path in dmsetup message.
|
||||
More libdevmapper-event interface changes and fixes.
|
||||
Rename dm_saprintf() to dm_asprintf().
|
||||
Report error if NULL pointer is supplied to dm_strdup_aux().
|
||||
Reinstate dm_event_get_registered_device.
|
||||
|
||||
Version 1.02.14 - 11th January 2007
|
||||
===================================
|
||||
Add dm_saprintf().
|
||||
|
||||
@@ -36,10 +36,10 @@
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <libdlm.h>
|
||||
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvm.h"
|
||||
#include "libdlm.h"
|
||||
#include "log.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
@@ -121,7 +121,7 @@ static int _get_num_nodes()
|
||||
|
||||
/* return number of ACTIVE nodes */
|
||||
for (i=0; i<num_nodes; i++) {
|
||||
if (nodes[i].cn_member)
|
||||
if (nodes[i].cn_member && nodes[i].cn_nodeid)
|
||||
nnodes++;
|
||||
}
|
||||
return nnodes;
|
||||
@@ -159,7 +159,7 @@ static int _cluster_do_node_callback(struct local_client *client,
|
||||
int somedown = 0;
|
||||
|
||||
for (i = 0; i < _get_num_nodes(); i++) {
|
||||
if (nodes[i].cn_member) {
|
||||
if (nodes[i].cn_member && nodes[i].cn_nodeid) {
|
||||
callback(client, (char *)&nodes[i].cn_nodeid, node_updown[nodes[i].cn_nodeid]);
|
||||
if (!node_updown[nodes[i].cn_nodeid])
|
||||
somedown = -1;
|
||||
@@ -168,8 +168,7 @@ static int _cluster_do_node_callback(struct local_client *client,
|
||||
return somedown;
|
||||
}
|
||||
|
||||
/* Process OOB message from the cluster socket,
|
||||
this currently just means that a node has stopped listening on our port */
|
||||
/* Process OOB messages from the cluster socket */
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
|
||||
{
|
||||
char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
|
||||
@@ -64,8 +64,9 @@
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <libdevmapper.h>
|
||||
#include <libdlm.h>
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "log.h"
|
||||
@@ -73,7 +74,6 @@
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd.h"
|
||||
#include "libdlm.h"
|
||||
|
||||
extern struct cluster_ops *clops;
|
||||
|
||||
|
||||
@@ -40,9 +40,10 @@
|
||||
#include <utmpx.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
#include <libdevmapper.h>
|
||||
#include <ccs.h>
|
||||
#include <libgulm.h>
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "ccs.h"
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "log.h"
|
||||
@@ -51,7 +52,6 @@
|
||||
#include "lvm-functions.h"
|
||||
#include "clvmd.h"
|
||||
#include "clvmd-gulm.h"
|
||||
#include "libgulm.h"
|
||||
|
||||
/* Hash list of nodes in the cluster */
|
||||
static struct dm_hash_table *node_hash;
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <getopt.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <libdlm.h>
|
||||
|
||||
#include "clvmd-comms.h"
|
||||
#include "lvm-functions.h"
|
||||
@@ -44,7 +45,6 @@
|
||||
#include "version.h"
|
||||
#include "clvmd.h"
|
||||
#include "refresh_clvmd.h"
|
||||
#include "libdlm.h"
|
||||
#include "system-lv.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
@@ -56,6 +56,8 @@
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define MAX_RETRIES 4
|
||||
|
||||
/* The maximum size of a message that will fit into a packet. Anything bigger
|
||||
than this is sent via the system LV */
|
||||
#define MAX_INLINE_MESSAGE (max_cluster_message-sizeof(struct clvm_header))
|
||||
@@ -325,7 +327,7 @@ int main(int argc, char *argv[])
|
||||
/* This needs to be started after cluster initialisation
|
||||
as it may need to take out locks */
|
||||
DEBUGLOG("starting LVM thread\n");
|
||||
pthread_create(&lvm_thread, NULL, lvm_thread_fn,
|
||||
pthread_create(&lvm_thread, NULL, lvm_thread_fn,
|
||||
(void *)(long)using_gulm);
|
||||
|
||||
/* Tell the rest of the cluster our version number */
|
||||
@@ -375,6 +377,9 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
|
||||
socklen_t sl = sizeof(socka);
|
||||
int client_fd = accept(thisfd->fd, (struct sockaddr *) &socka, &sl);
|
||||
|
||||
if (client_fd == -1 && errno == EINTR)
|
||||
return 1;
|
||||
|
||||
if (client_fd >= 0) {
|
||||
newfd = malloc(sizeof(struct local_client));
|
||||
if (!newfd) {
|
||||
@@ -412,6 +417,8 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
|
||||
int status = -1; /* in error by default */
|
||||
|
||||
len = read(thisfd->fd, buffer, sizeof(int));
|
||||
if (len == -1 && errno == EINTR)
|
||||
return 1;
|
||||
|
||||
if (len == sizeof(int)) {
|
||||
memcpy(&status, buffer, sizeof(int));
|
||||
@@ -786,6 +793,8 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
char buffer[PIPE_BUF];
|
||||
|
||||
len = read(thisfd->fd, buffer, sizeof(buffer));
|
||||
if (len == -1 && errno == EINTR)
|
||||
return 1;
|
||||
|
||||
DEBUGLOG("Read on local socket %d, len = %d\n", thisfd->fd, len);
|
||||
|
||||
@@ -901,8 +910,12 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
len - strlen(inheader->node) - sizeof(struct clvm_header);
|
||||
missing_len = inheader->arglen - argslen;
|
||||
|
||||
if (missing_len < 0)
|
||||
missing_len = 0;
|
||||
|
||||
/* Save the message */
|
||||
thisfd->bits.localsock.cmd = malloc(len + missing_len);
|
||||
|
||||
if (!thisfd->bits.localsock.cmd) {
|
||||
struct clvm_header reply;
|
||||
reply.cmd = CLVMD_CMD_REPLY;
|
||||
@@ -927,9 +940,8 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
DEBUGLOG
|
||||
("got %d bytes, need another %d (total %d)\n",
|
||||
argslen, missing_len, inheader->arglen);
|
||||
len =
|
||||
read(thisfd->fd, argptr + argslen,
|
||||
missing_len);
|
||||
len = read(thisfd->fd, argptr + argslen,
|
||||
missing_len);
|
||||
if (len >= 0) {
|
||||
missing_len -= len;
|
||||
argslen += len;
|
||||
@@ -1215,7 +1227,7 @@ static void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
/* Version check is internal - don't bother exposing it in
|
||||
clvmd-command.c */
|
||||
if (msg->cmd == CLVMD_CMD_VERSION) {
|
||||
int version_nums[3];
|
||||
int version_nums[3];
|
||||
char node[256];
|
||||
|
||||
memcpy(version_nums, msg->args, sizeof(version_nums));
|
||||
@@ -1395,6 +1407,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
|
||||
{
|
||||
struct local_client *client = (struct local_client *) arg;
|
||||
int status;
|
||||
int write_status;
|
||||
sigset_t ss;
|
||||
int pipe_fd = client->bits.localsock.pipe;
|
||||
|
||||
@@ -1424,8 +1437,19 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
|
||||
client->bits.localsock.all_success = 0;
|
||||
|
||||
DEBUGLOG("Writing status %d down pipe %d\n", status, pipe_fd);
|
||||
|
||||
/* Tell the parent process we have finished this bit */
|
||||
write(pipe_fd, &status, sizeof(int));
|
||||
do {
|
||||
write_status = write(pipe_fd, &status, sizeof(int));
|
||||
if (write_status == sizeof(int))
|
||||
break;
|
||||
if (write_status < 0 &&
|
||||
(errno == EINTR || errno == EAGAIN))
|
||||
continue;
|
||||
log_error("Error sending to pipe: %m\n");
|
||||
break;
|
||||
} while(1);
|
||||
|
||||
if (status)
|
||||
continue; /* Wait for another PRE command */
|
||||
|
||||
@@ -1446,7 +1470,16 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
|
||||
status = 0;
|
||||
do_post_command(client);
|
||||
|
||||
write(pipe_fd, &status, sizeof(int));
|
||||
do {
|
||||
write_status = write(pipe_fd, &status, sizeof(int));
|
||||
if (write_status == sizeof(int))
|
||||
break;
|
||||
if (write_status < 0 &&
|
||||
(errno == EINTR || errno == EAGAIN))
|
||||
continue;
|
||||
log_error("Error sending to pipe: %m\n");
|
||||
break;
|
||||
} while(1);
|
||||
|
||||
DEBUGLOG("Waiting for next pre command\n");
|
||||
|
||||
@@ -1650,6 +1683,11 @@ static int send_message(void *buf, int msglen, char *csid, int fd,
|
||||
const char *errtext)
|
||||
{
|
||||
int len;
|
||||
int saved_errno = 0;
|
||||
struct timespec delay;
|
||||
struct timespec remtime;
|
||||
|
||||
int retry_cnt = 0;
|
||||
|
||||
/* Send remote messages down the cluster socket */
|
||||
if (csid == NULL || !ISLOCAL_CSID(csid)) {
|
||||
@@ -1660,14 +1698,38 @@ static int send_message(void *buf, int msglen, char *csid, int fd,
|
||||
|
||||
/* Make sure it all goes */
|
||||
do {
|
||||
if (retry_cnt > MAX_RETRIES)
|
||||
{
|
||||
errno = saved_errno;
|
||||
log_error(errtext);
|
||||
errno = saved_errno;
|
||||
break;
|
||||
}
|
||||
|
||||
len = write(fd, buf + ptr, msglen - ptr);
|
||||
|
||||
if (len <= 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (errno == EAGAIN ||
|
||||
errno == EIO ||
|
||||
errno == ENOSPC) {
|
||||
saved_errno = errno;
|
||||
retry_cnt++;
|
||||
|
||||
delay.tv_sec = 0;
|
||||
delay.tv_nsec = 100000;
|
||||
remtime.tv_sec = 0;
|
||||
remtime.tv_nsec = 0;
|
||||
(void) nanosleep (&delay, &remtime);
|
||||
|
||||
continue;
|
||||
}
|
||||
log_error(errtext);
|
||||
break;
|
||||
}
|
||||
ptr += len;
|
||||
} while (len < msglen);
|
||||
} while (ptr < msglen);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
#include <libdevmapper.h>
|
||||
#include <libdlm.h>
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "list.h"
|
||||
#include "lvm-types.h"
|
||||
#include "libdlm.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
@@ -50,6 +50,7 @@
|
||||
static struct cmd_context *cmd = NULL;
|
||||
static struct dm_hash_table *lv_hash = NULL;
|
||||
static pthread_mutex_t lv_hash_lock;
|
||||
static pthread_mutex_t lvm_lock;
|
||||
static char last_error[1024];
|
||||
|
||||
struct lv_info {
|
||||
@@ -311,10 +312,12 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
DEBUGLOG("do_lock_lv: resource '%s', cmd = 0x%x, flags = %x\n",
|
||||
resource, command, lock_flags);
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
if (!cmd->config_valid || config_files_changed(cmd)) {
|
||||
/* Reinitialise various settings inc. logging, filters */
|
||||
if (!refresh_toolcontext(cmd)) {
|
||||
log_error("Updated config file invalid. Aborting.");
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
@@ -325,8 +328,8 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(1);
|
||||
|
||||
if (!(lock_flags & LCK_DMEVENTD_REGISTER_MODE))
|
||||
init_dmeventd_register(0);
|
||||
if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE))
|
||||
init_dmeventd_monitor(0);
|
||||
|
||||
switch (command) {
|
||||
case LCK_LV_EXCLUSIVE:
|
||||
@@ -362,11 +365,12 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(0);
|
||||
|
||||
if (!(lock_flags & LCK_DMEVENTD_REGISTER_MODE))
|
||||
init_dmeventd_register(DEFAULT_DMEVENTD_MONITOR);
|
||||
if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE))
|
||||
init_dmeventd_monitor(DEFAULT_DMEVENTD_MONITOR);
|
||||
|
||||
/* clean the pool for another command */
|
||||
dm_pool_empty(cmd->mem);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
|
||||
DEBUGLOG("Command return is %d\n", status);
|
||||
return status;
|
||||
@@ -393,6 +397,8 @@ int pre_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
int post_lock_lv(unsigned char command, unsigned char lock_flags,
|
||||
char *resource)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* Opposite of above, done on resume after a metadata update */
|
||||
if (command == LCK_LV_RESUME) {
|
||||
int oldmode;
|
||||
@@ -406,7 +412,10 @@ int post_lock_lv(unsigned char command, unsigned char lock_flags,
|
||||
if (oldmode == LKM_PWMODE) {
|
||||
struct lvinfo lvi;
|
||||
|
||||
if (!lv_info_by_lvid(cmd, resource, &lvi, 0))
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
status = lv_info_by_lvid(cmd, resource, &lvi, 0);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
if (!status)
|
||||
return EIO;
|
||||
|
||||
if (lvi.exists) {
|
||||
@@ -473,7 +482,8 @@ static void drop_vg_locks()
|
||||
sync_unlock(vg, LCK_EXCL);
|
||||
|
||||
}
|
||||
fclose(vgs);
|
||||
if (fclose(vgs))
|
||||
DEBUGLOG("vgs fclose failed: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -523,7 +533,8 @@ static void *get_initial_state()
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(lvs);
|
||||
if (fclose(lvs))
|
||||
DEBUGLOG("lvs fclose failed: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -531,7 +542,7 @@ static void lvm2_log_fn(int level, const char *file, int line,
|
||||
const char *message)
|
||||
{
|
||||
/*
|
||||
* Ignore non-error messages, but store the latest one for returning
|
||||
* Ignore non-error messages, but store the latest one for returning
|
||||
* to the user.
|
||||
*/
|
||||
if (level != _LOG_ERR && level != _LOG_FATAL)
|
||||
@@ -570,12 +581,13 @@ void init_lvhash()
|
||||
/* Create hash table for keeping LV locks & status */
|
||||
lv_hash = dm_hash_create(100);
|
||||
pthread_mutex_init(&lv_hash_lock, NULL);
|
||||
pthread_mutex_init(&lvm_lock, NULL);
|
||||
}
|
||||
|
||||
/* Called to initialise the LVM context of the daemon */
|
||||
int init_lvm(int using_gulm)
|
||||
{
|
||||
if (!(cmd = create_toolcontext(NULL, 0))) {
|
||||
if (!(cmd = create_toolcontext(NULL, 0, 1))) {
|
||||
log_error("Failed to allocate command context");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -36,8 +36,11 @@
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <mntent.h>
|
||||
#include <libdlm.h>
|
||||
#ifdef HAVE_CCS
|
||||
#include <ccs.h>
|
||||
#endif
|
||||
|
||||
#include "libdlm.h"
|
||||
#include "log.h"
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
@@ -45,9 +48,6 @@
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#ifdef HAVE_CCS
|
||||
#include "ccs.h"
|
||||
#endif
|
||||
|
||||
#define SYSTEM_LV_FILESYSTEM "ext2"
|
||||
#define SYSTEM_LV_MOUNTPOINT "/tmp/.clvmd-XXXXXX"
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
#include <syslog.h>
|
||||
#include <netdb.h>
|
||||
#include <assert.h>
|
||||
#include <libdevmapper.h>
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
dm_event_handler_create
|
||||
dm_event_handler_destroy
|
||||
dm_event_handler_set_dso
|
||||
dm_event_handler_set_name
|
||||
dm_event_handler_set_dev_name
|
||||
dm_event_handler_set_uuid
|
||||
dm_event_handler_set_major
|
||||
dm_event_handler_set_minor
|
||||
dm_event_handler_set_events
|
||||
dm_event_handler_set_event_mask
|
||||
dm_event_handler_get_dso
|
||||
dm_event_handler_get_name
|
||||
dm_event_handler_get_devname
|
||||
dm_event_handler_get_uuid
|
||||
dm_event_handler_get_major
|
||||
dm_event_handler_get_minor
|
||||
dm_event_handler_get_events
|
||||
dm_event_register
|
||||
dm_event_unregister
|
||||
dm_event_handler_get_event_mask
|
||||
dm_event_register_handler
|
||||
dm_event_unregister_handler
|
||||
dm_event_get_registered_device
|
||||
dm_event_handler_set_timeout
|
||||
dm_event_handler_get_timeout
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@ enum dm_event_command {
|
||||
DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
|
||||
DM_EVENT_CMD_SET_TIMEOUT,
|
||||
DM_EVENT_CMD_GET_TIMEOUT,
|
||||
DM_EVENT_CMD_HELLO,
|
||||
};
|
||||
|
||||
/* Message passed between client and daemon. */
|
||||
|
||||
@@ -30,110 +30,173 @@
|
||||
#include <sys/wait.h>
|
||||
#include <arpa/inet.h> /* for htonl, ntohl */
|
||||
|
||||
static int _sequence_nr = 0;
|
||||
|
||||
struct dm_event_handler {
|
||||
const char *dso;
|
||||
const char *device;
|
||||
const char *uuid;
|
||||
char *dso;
|
||||
|
||||
char *dev_name;
|
||||
|
||||
char *uuid;
|
||||
int major;
|
||||
int minor;
|
||||
enum dm_event_type events;
|
||||
uint32_t timeout;
|
||||
|
||||
enum dm_event_mask mask;
|
||||
};
|
||||
|
||||
static void dm_event_handler_clear_device(struct dm_event_handler *h)
|
||||
static void _dm_event_handler_clear_dev_info(struct dm_event_handler *dmevh)
|
||||
{
|
||||
h->device = h->uuid = NULL;
|
||||
h->major = h->minor = 0;
|
||||
if (dmevh->dev_name)
|
||||
dm_free(dmevh->dev_name);
|
||||
if (dmevh->uuid)
|
||||
dm_free(dmevh->uuid);
|
||||
dmevh->dev_name = dmevh->uuid = NULL;
|
||||
dmevh->major = dmevh->minor = 0;
|
||||
}
|
||||
|
||||
struct dm_event_handler *dm_event_handler_create(void)
|
||||
{
|
||||
struct dm_event_handler *ret = 0;
|
||||
struct dm_event_handler *dmevh = NULL;
|
||||
|
||||
if (!(ret = dm_malloc(sizeof(*ret))))
|
||||
if (!(dmevh = dm_malloc(sizeof(*dmevh))))
|
||||
return NULL;
|
||||
|
||||
ret->dso = ret->device = ret->uuid = NULL;
|
||||
ret->major = ret->minor = 0;
|
||||
ret->events = 0;
|
||||
dmevh->dso = dmevh->dev_name = dmevh->uuid = NULL;
|
||||
dmevh->major = dmevh->minor = 0;
|
||||
dmevh->mask = 0;
|
||||
dmevh->timeout = 0;
|
||||
|
||||
return ret;
|
||||
return dmevh;
|
||||
}
|
||||
|
||||
void dm_event_handler_destroy(struct dm_event_handler *h)
|
||||
void dm_event_handler_destroy(struct dm_event_handler *dmevh)
|
||||
{
|
||||
dm_free(h);
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
if (dmevh->dso)
|
||||
dm_free(dmevh->dso);
|
||||
dm_free(dmevh);
|
||||
}
|
||||
|
||||
void dm_event_handler_set_dso(struct dm_event_handler *h, const char *path)
|
||||
int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path)
|
||||
{
|
||||
h->dso = path;
|
||||
if (!path) /* noop */
|
||||
return 0;
|
||||
if (dmevh->dso)
|
||||
dm_free(dmevh->dso);
|
||||
|
||||
dmevh->dso = dm_strdup(path);
|
||||
if (!dmevh->dso)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dm_event_handler_set_name(struct dm_event_handler *h, const char *name)
|
||||
int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *dev_name)
|
||||
{
|
||||
dm_event_handler_clear_device(h);
|
||||
h->device = name;
|
||||
if (!dev_name)
|
||||
return 0;
|
||||
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
|
||||
dmevh->dev_name = dm_strdup(dev_name);
|
||||
if (!dmevh->dev_name)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dm_event_handler_set_uuid(struct dm_event_handler *h, const char *uuid)
|
||||
int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid)
|
||||
{
|
||||
dm_event_handler_clear_device(h);
|
||||
h->uuid = uuid;
|
||||
if (!uuid)
|
||||
return 0;
|
||||
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
|
||||
dmevh->uuid = dm_strdup(uuid);
|
||||
if (!dmevh->dev_name)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dm_event_handler_set_major(struct dm_event_handler *h, int major)
|
||||
void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major)
|
||||
{
|
||||
int minor = h->minor;
|
||||
int minor = dmevh->minor;
|
||||
|
||||
dm_event_handler_clear_device(h);
|
||||
h->major = major;
|
||||
h->minor = minor;
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
|
||||
dmevh->major = major;
|
||||
dmevh->minor = minor;
|
||||
}
|
||||
|
||||
void dm_event_handler_set_minor(struct dm_event_handler *h, int minor)
|
||||
void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor)
|
||||
{
|
||||
int major = h->major;
|
||||
int major = dmevh->major;
|
||||
|
||||
dm_event_handler_clear_device(h);
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
|
||||
h->major = major;
|
||||
h->minor = minor;
|
||||
dmevh->major = major;
|
||||
dmevh->minor = minor;
|
||||
}
|
||||
|
||||
void dm_event_handler_set_events(struct dm_event_handler *h,
|
||||
enum dm_event_type event)
|
||||
void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh,
|
||||
enum dm_event_mask evmask)
|
||||
{
|
||||
h->events = event;
|
||||
dmevh->mask = evmask;
|
||||
}
|
||||
|
||||
const char *dm_event_handler_get_dso(const struct dm_event_handler *h)
|
||||
void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout)
|
||||
{
|
||||
return h->dso;
|
||||
dmevh->timeout = timeout;
|
||||
}
|
||||
|
||||
const char *dm_event_handler_get_name(const struct dm_event_handler *h)
|
||||
const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
return h->device;
|
||||
return dmevh->dso;
|
||||
}
|
||||
|
||||
const char *dm_event_handler_get_uuid(const struct dm_event_handler *h)
|
||||
const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
return h->uuid;
|
||||
return dmevh->dev_name;
|
||||
}
|
||||
|
||||
int dm_event_handler_get_major(const struct dm_event_handler *h)
|
||||
const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
return h->major;
|
||||
return dmevh->uuid;
|
||||
}
|
||||
|
||||
int dm_event_handler_get_minor(const struct dm_event_handler *h)
|
||||
int dm_event_handler_get_major(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
return h->minor;
|
||||
return dmevh->major;
|
||||
}
|
||||
|
||||
enum dm_event_type dm_event_handler_get_events(const struct dm_event_handler *h)
|
||||
int dm_event_handler_get_minor(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
return h->events;
|
||||
return dmevh->minor;
|
||||
}
|
||||
|
||||
int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
return dmevh->timeout;
|
||||
}
|
||||
|
||||
enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
return dmevh->mask;
|
||||
}
|
||||
|
||||
static int _check_message_id(struct dm_event_daemon_message *msg)
|
||||
{
|
||||
int pid, seq_nr;
|
||||
|
||||
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(),
|
||||
_sequence_nr, msg->data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -145,8 +208,8 @@ enum dm_event_type dm_event_handler_get_events(const struct dm_event_handler *h)
|
||||
*
|
||||
* Returns: 0 on failure, 1 on success
|
||||
*/
|
||||
static int daemon_read(struct dm_event_fifos *fifos,
|
||||
struct dm_event_daemon_message *msg)
|
||||
static int _daemon_read(struct dm_event_fifos *fifos,
|
||||
struct dm_event_daemon_message *msg)
|
||||
{
|
||||
unsigned bytes = 0;
|
||||
int ret, i;
|
||||
@@ -205,8 +268,8 @@ static int daemon_read(struct dm_event_fifos *fifos,
|
||||
}
|
||||
|
||||
/* Write message to daemon. */
|
||||
static int daemon_write(struct dm_event_fifos *fifos,
|
||||
struct dm_event_daemon_message *msg)
|
||||
static int _daemon_write(struct dm_event_fifos *fifos,
|
||||
struct dm_event_daemon_message *msg)
|
||||
{
|
||||
unsigned bytes = 0;
|
||||
int ret = 0;
|
||||
@@ -214,11 +277,28 @@ static int daemon_write(struct dm_event_fifos *fifos,
|
||||
|
||||
size_t size = 2 * sizeof(uint32_t) + msg->size;
|
||||
char *buf = alloca(size);
|
||||
char drainbuf[128];
|
||||
struct timeval tval = { 0, 0 };
|
||||
|
||||
*((uint32_t *)buf) = htonl(msg->cmd);
|
||||
*((uint32_t *)buf + 1) = htonl(msg->size);
|
||||
memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size);
|
||||
|
||||
/* drain the answer fifo */
|
||||
while (1) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fifos->server, &fds);
|
||||
tval.tv_usec = 100;
|
||||
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
|
||||
if ((ret < 0) && (errno != EINTR)) {
|
||||
log_error("Unable to talk to event daemon");
|
||||
return 0;
|
||||
}
|
||||
if (ret == 0)
|
||||
break;
|
||||
read(fifos->server, drainbuf, 127);
|
||||
}
|
||||
|
||||
while (bytes < size) {
|
||||
do {
|
||||
/* Watch daemon write FIFO to be ready for output. */
|
||||
@@ -248,14 +328,15 @@ static int daemon_write(struct dm_event_fifos *fifos,
|
||||
return bytes == size;
|
||||
}
|
||||
|
||||
static int daemon_talk(struct dm_event_fifos *fifos,
|
||||
struct dm_event_daemon_message *msg, int cmd,
|
||||
const char *dso_name, const char *device,
|
||||
enum dm_event_type events, uint32_t timeout)
|
||||
static int _daemon_talk(struct dm_event_fifos *fifos,
|
||||
struct dm_event_daemon_message *msg, int cmd,
|
||||
const char *dso_name, const char *dev_name,
|
||||
enum dm_event_mask evmask, uint32_t timeout)
|
||||
{
|
||||
const char *dso = dso_name ? dso_name : "";
|
||||
const char *dev = device ? device : "";
|
||||
const char *fmt = "%s %s %u %" PRIu32;
|
||||
const char *dev = dev_name ? dev_name : "";
|
||||
const char *fmt = "%d:%d %s %s %u %" PRIu32;
|
||||
int msg_size;
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
|
||||
/*
|
||||
@@ -263,21 +344,39 @@ static int daemon_talk(struct dm_event_fifos *fifos,
|
||||
* into ASCII message string.
|
||||
*/
|
||||
msg->cmd = cmd;
|
||||
msg->size = dm_saprintf(&(msg->data), fmt, dso, dev, events, timeout);
|
||||
if (cmd == DM_EVENT_CMD_HELLO)
|
||||
fmt = "%d:%d HELLO";
|
||||
if ((msg_size = dm_asprintf(&(msg->data), fmt, getpid(), _sequence_nr,
|
||||
dso, dev, evmask, timeout)) < 0) {
|
||||
log_error("_daemon_talk: message allocation failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
msg->size = msg_size;
|
||||
|
||||
/*
|
||||
* Write command and message to and
|
||||
* read status return code from daemon.
|
||||
*/
|
||||
if (!daemon_write(fifos, msg)) {
|
||||
if (!_daemon_write(fifos, msg)) {
|
||||
stack;
|
||||
dm_free(msg->data);
|
||||
msg->data = 0;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!daemon_read(fifos, msg)) {
|
||||
stack;
|
||||
return -EIO;
|
||||
}
|
||||
do {
|
||||
|
||||
if (msg->data)
|
||||
dm_free(msg->data);
|
||||
msg->data = 0;
|
||||
|
||||
if (!_daemon_read(fifos, msg)) {
|
||||
stack;
|
||||
return -EIO;
|
||||
}
|
||||
} while (!_check_message_id(msg));
|
||||
|
||||
_sequence_nr++;
|
||||
|
||||
return (int32_t) msg->cmd;
|
||||
}
|
||||
@@ -294,7 +393,7 @@ static int daemon_talk(struct dm_event_fifos *fifos,
|
||||
*
|
||||
* Returns: 1 on success, 0 otherwise
|
||||
*/
|
||||
static int start_daemon(struct dm_event_fifos *fifos)
|
||||
static int _start_daemon(struct dm_event_fifos *fifos)
|
||||
{
|
||||
int pid, ret = 0;
|
||||
int status;
|
||||
@@ -332,8 +431,7 @@ static int start_daemon(struct dm_event_fifos *fifos)
|
||||
log_error("Unable to fork.");
|
||||
|
||||
else if (!pid) {
|
||||
/* FIXME configure path (cf. lvm2 modprobe) */
|
||||
execvp("dmeventd", NULL);
|
||||
execvp(DMEVENTD_PATH, NULL);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
if (waitpid(pid, &status, 0) < 0)
|
||||
@@ -349,7 +447,7 @@ static int start_daemon(struct dm_event_fifos *fifos)
|
||||
}
|
||||
|
||||
/* Initialize client. */
|
||||
static int init_client(struct dm_event_fifos *fifos)
|
||||
static int _init_client(struct dm_event_fifos *fifos)
|
||||
{
|
||||
/* FIXME? Is fifo the most suitable method? Why not share
|
||||
comms/daemon code with something else e.g. multipath? */
|
||||
@@ -359,7 +457,7 @@ static int init_client(struct dm_event_fifos *fifos)
|
||||
fifos->client_path = DM_EVENT_FIFO_CLIENT;
|
||||
fifos->server_path = DM_EVENT_FIFO_SERVER;
|
||||
|
||||
if (!start_daemon(fifos)) {
|
||||
if (!_start_daemon(fifos)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -391,7 +489,7 @@ static int init_client(struct dm_event_fifos *fifos)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void dtr_client(struct dm_event_fifos *fifos)
|
||||
static void _dtr_client(struct dm_event_fifos *fifos)
|
||||
{
|
||||
if (flock(fifos->server, LOCK_UN))
|
||||
log_error("flock unlock %s", fifos->server_path);
|
||||
@@ -400,76 +498,99 @@ static void dtr_client(struct dm_event_fifos *fifos)
|
||||
close(fifos->server);
|
||||
}
|
||||
|
||||
/* Get uuid of a device, if it exists (otherwise NULL). */
|
||||
static struct dm_task *get_device_info(const struct dm_event_handler *h)
|
||||
/* Get uuid of a device */
|
||||
static struct dm_task *_get_device_info(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
struct dm_task *dmt = dm_task_create(DM_DEVICE_INFO);
|
||||
struct dm_task *ret;
|
||||
struct dm_task *dmt;
|
||||
struct dm_info info;
|
||||
|
||||
if (!dmt)
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
|
||||
log_error("_get_device_info: dm_task creation for info failed");
|
||||
return NULL;
|
||||
|
||||
if (h->uuid)
|
||||
dm_task_set_uuid(dmt, h->uuid);
|
||||
else if (h->device)
|
||||
dm_task_set_name(dmt, h->device);
|
||||
else if (h->major && h->minor) {
|
||||
dm_task_set_major(dmt, h->major);
|
||||
dm_task_set_minor(dmt, h->minor);
|
||||
}
|
||||
|
||||
if (!dm_task_run(dmt))
|
||||
ret = NULL;
|
||||
else
|
||||
ret = dmt;
|
||||
if (dmevh->uuid)
|
||||
dm_task_set_uuid(dmt, dmevh->uuid);
|
||||
else if (dmevh->dev_name)
|
||||
dm_task_set_name(dmt, dmevh->dev_name);
|
||||
else if (dmevh->major && dmevh->minor) {
|
||||
dm_task_set_major(dmt, dmevh->major);
|
||||
dm_task_set_minor(dmt, dmevh->minor);
|
||||
}
|
||||
|
||||
return ret;
|
||||
/* FIXME Add name or uuid or devno to messages */
|
||||
if (!dm_task_run(dmt)) {
|
||||
log_error("_get_device_info: dm_task_run() failed");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (!dm_task_get_info(dmt, &info)) {
|
||||
log_error("_get_device_info: failed to get info for device");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (!info.exists) {
|
||||
log_error("_get_device_info: device not found");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return dmt;
|
||||
|
||||
failed:
|
||||
dm_task_destroy(dmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Handle the event (de)registration call and return negative error codes. */
|
||||
static int do_event(int cmd, struct dm_event_daemon_message *msg,
|
||||
const char *dso_name, const char *device,
|
||||
enum dm_event_type events, uint32_t timeout)
|
||||
static int _do_event(int cmd, struct dm_event_daemon_message *msg,
|
||||
const char *dso_name, const char *dev_name,
|
||||
enum dm_event_mask evmask, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct dm_event_fifos fifos;
|
||||
|
||||
if (!init_client(&fifos)) {
|
||||
if (!_init_client(&fifos)) {
|
||||
stack;
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
ret = daemon_talk(&fifos, msg, cmd, dso_name, device, events, timeout);
|
||||
ret = _daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, 0, 0, 0, 0);
|
||||
|
||||
if (msg->data)
|
||||
dm_free(msg->data);
|
||||
msg->data = 0;
|
||||
|
||||
if (!ret)
|
||||
ret = _daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
|
||||
|
||||
/* what is the opposite of init? */
|
||||
dtr_client(&fifos);
|
||||
_dtr_client(&fifos);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* External library interface. */
|
||||
int dm_event_register(const struct dm_event_handler *h)
|
||||
int dm_event_register_handler(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
int ret, err;
|
||||
int ret = 1, err;
|
||||
const char *uuid;
|
||||
struct dm_task *dmt;
|
||||
struct dm_event_daemon_message msg;
|
||||
struct dm_event_daemon_message msg = { 0, 0, NULL };
|
||||
|
||||
if (!(dmt = get_device_info(h))) {
|
||||
log_error("%s: device not found", h->device);
|
||||
if (!(dmt = _get_device_info(dmevh))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uuid = dm_task_get_uuid(dmt);
|
||||
|
||||
if ((err = do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
|
||||
h->dso, uuid, h->events, 0)) < 0) {
|
||||
if ((err = _do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
|
||||
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
|
||||
log_error("%s: event registration failed: %s",
|
||||
dm_task_get_name(dmt),
|
||||
msg.data ? msg.data : strerror(-err));
|
||||
ret = 0;
|
||||
} else
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (msg.data)
|
||||
dm_free(msg.data);
|
||||
@@ -479,28 +600,27 @@ int dm_event_register(const struct dm_event_handler *h)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dm_event_unregister(const struct dm_event_handler *h)
|
||||
int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
|
||||
{
|
||||
int ret, err;
|
||||
int ret = 1, err;
|
||||
const char *uuid;
|
||||
struct dm_task *dmt;
|
||||
struct dm_event_daemon_message msg;
|
||||
struct dm_event_daemon_message msg = { 0, 0, NULL };
|
||||
|
||||
if (!(dmt = get_device_info(h))) {
|
||||
log_error("%s: device not found", dm_task_get_name(dmt));
|
||||
if (!(dmt = _get_device_info(dmevh))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uuid = dm_task_get_uuid(dmt);
|
||||
|
||||
if ((err = do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
|
||||
h->dso, uuid, h->events, 0)) < 0) {
|
||||
if ((err = _do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
|
||||
dmevh->dso, uuid, dmevh->mask, dmevh->timeout)) < 0) {
|
||||
log_error("%s: event deregistration failed: %s",
|
||||
dm_task_get_name(dmt),
|
||||
msg.data ? msg.data : strerror(-err));
|
||||
ret = 0;
|
||||
} else
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (msg.data)
|
||||
dm_free(msg.data);
|
||||
@@ -510,12 +630,9 @@ int dm_event_unregister(const struct dm_event_handler *h)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0 /* left out for now */
|
||||
|
||||
/* Fetch a string off src and duplicate it into *dest. */
|
||||
/* FIXME: move to seperate module to share with the daemon. */
|
||||
static const char delimiter = ' ';
|
||||
static char *fetch_string(char **src)
|
||||
/* FIXME: move to separate module to share with the daemon. */
|
||||
static char *_fetch_string(char **src, const int delimiter)
|
||||
{
|
||||
char *p, *ret;
|
||||
|
||||
@@ -532,17 +649,23 @@ static char *fetch_string(char **src)
|
||||
}
|
||||
|
||||
/* Parse a device message from the daemon. */
|
||||
static int parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
||||
char **device, enum dm_event_type *events)
|
||||
static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
||||
char **uuid, enum dm_event_mask *evmask)
|
||||
{
|
||||
char *id = NULL;
|
||||
char *p = msg->data;
|
||||
|
||||
if ((*dso_name = fetch_string(&p)) && (*device = fetch_string(&p))) {
|
||||
*events = atoi(p);
|
||||
if ((id = _fetch_string(&p, ' ')) &&
|
||||
(*dso_name = _fetch_string(&p, ' ')) &&
|
||||
(*uuid = _fetch_string(&p, ' '))) {
|
||||
*evmask = atoi(p);
|
||||
|
||||
dm_free(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (id)
|
||||
dm_free(id);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -550,68 +673,134 @@ static int parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
||||
* dm_event_get_registered_device
|
||||
* @dso_name
|
||||
* @device_path
|
||||
* @events
|
||||
* @mask
|
||||
* @next
|
||||
*
|
||||
* FIXME: This function sucks.
|
||||
*
|
||||
* Returns: 1 if device found, 0 otherwise (even on error)
|
||||
* Returns: 0 if handler found, error (-ENOMEM, -ENOENT) otherwise
|
||||
*/
|
||||
int dm_event_get_registered_device(char **dso_name, char **device_path,
|
||||
enum dm_event_type *events, int next)
|
||||
int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
{
|
||||
int ret;
|
||||
char *dso_name_arg = NULL, *device_path_arg = NULL;
|
||||
struct dm_event_daemon_message msg;
|
||||
int ret = 0;
|
||||
const char *uuid = NULL;
|
||||
char *reply_dso = NULL, *reply_uuid = NULL;
|
||||
enum dm_event_mask reply_mask = 0;
|
||||
struct dm_task *dmt = NULL;
|
||||
struct dm_event_daemon_message msg = { 0, 0, NULL };
|
||||
|
||||
if (!(ret = do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
|
||||
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
|
||||
&msg, *dso_name, *device_path, *events, 0))) {
|
||||
ret = !parse_message(&msg, &dso_name_arg, &device_path_arg,
|
||||
events);
|
||||
} else /* FIXME: Make sure this is ENOENT */
|
||||
ret = 0;
|
||||
|
||||
if (msg.data)
|
||||
dm_free(msg.data);
|
||||
|
||||
if (next) {
|
||||
if (*dso_name)
|
||||
dm_free(*dso_name);
|
||||
if (*device_path)
|
||||
dm_free(*device_path);
|
||||
*dso_name = dso_name_arg;
|
||||
*device_path = device_path_arg;
|
||||
} else {
|
||||
if (!(*dso_name))
|
||||
*dso_name = dso_name_arg;
|
||||
if (!(*device_path))
|
||||
*device_path = device_path_arg;
|
||||
if (!(dmt = _get_device_info(dmevh))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uuid = dm_task_get_uuid(dmt);
|
||||
|
||||
if (!(ret = _do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
|
||||
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
|
||||
&msg, dmevh->dso, uuid, dmevh->mask, 0))) {
|
||||
/* FIXME this will probably horribly break if we get
|
||||
ill-formatted reply */
|
||||
ret = _parse_message(&msg, &reply_dso, &reply_uuid, &reply_mask);
|
||||
} else {
|
||||
ret = -ENOENT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
if (msg.data) {
|
||||
dm_free(msg.data);
|
||||
msg.data = NULL;
|
||||
}
|
||||
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
dmevh->uuid = dm_strdup(reply_uuid);
|
||||
if (!dmevh->uuid) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(dmt = _get_device_info(dmevh))) {
|
||||
ret = -ENXIO; /* dmeventd probably gave us bogus uuid back */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dm_event_handler_set_dso(dmevh, reply_dso);
|
||||
dm_event_handler_set_event_mask(dmevh, reply_mask);
|
||||
|
||||
if (reply_dso)
|
||||
dm_free(reply_dso);
|
||||
if (reply_uuid)
|
||||
dm_free(reply_uuid);
|
||||
|
||||
dmevh->dev_name = dm_strdup(dm_task_get_name(dmt));
|
||||
if (!dmevh->dev_name) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
struct dm_info info;
|
||||
if (!dm_task_get_info(dmt, &info)) {
|
||||
ret = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dmevh->major = info.major;
|
||||
dmevh->minor = info.minor;
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
if (msg.data)
|
||||
dm_free(msg.data);
|
||||
if (reply_dso)
|
||||
dm_free(reply_dso);
|
||||
if (reply_uuid)
|
||||
dm_free(reply_uuid);
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
dm_task_destroy(dmt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0 /* left out for now */
|
||||
|
||||
static char *_skip_string(char *src, const int delimiter)
|
||||
{
|
||||
src = srtchr(src, delimiter);
|
||||
if (src && *(src + 1))
|
||||
return src + 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dm_event_set_timeout(const char *device_path, uint32_t timeout)
|
||||
{
|
||||
struct dm_event_daemon_message msg;
|
||||
struct dm_event_daemon_message msg = { 0, 0, NULL };
|
||||
|
||||
if (!device_exists(device_path))
|
||||
return -ENODEV;
|
||||
return do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg,
|
||||
NULL, device_path, 0, timeout);
|
||||
|
||||
return _do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg,
|
||||
NULL, device_path, 0, timeout);
|
||||
}
|
||||
|
||||
int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
|
||||
{
|
||||
int ret;
|
||||
struct dm_event_daemon_message msg;
|
||||
struct dm_event_daemon_message msg = { 0, 0, NULL };
|
||||
|
||||
if (!device_exists(device_path))
|
||||
return -ENODEV;
|
||||
if (!(ret = do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path,
|
||||
0, 0)))
|
||||
*timeout = atoi(msg.data);
|
||||
if (!(ret = _do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path,
|
||||
0, 0))) {
|
||||
char *p = _skip_string(msg.data, ' ');
|
||||
if (!p) {
|
||||
log_error("malformed reply from dmeventd '%s'\n",
|
||||
msg.data);
|
||||
return -EIO;
|
||||
}
|
||||
*timeout = atoi(p);
|
||||
}
|
||||
if (msg.data)
|
||||
dm_free(msg.data);
|
||||
return ret;
|
||||
|
||||
@@ -23,8 +23,11 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Event type definitions. */
|
||||
enum dm_event_type {
|
||||
/*
|
||||
* Event library interface.
|
||||
*/
|
||||
|
||||
enum dm_event_mask {
|
||||
DM_EVENT_SETTINGS_MASK = 0x0000FF,
|
||||
DM_EVENT_SINGLE = 0x000001, /* Report multiple errors just once. */
|
||||
DM_EVENT_MULTI = 0x000002, /* Report all of them. */
|
||||
@@ -33,7 +36,7 @@ enum dm_event_type {
|
||||
DM_EVENT_SECTOR_ERROR = 0x000100, /* Failure on a particular sector. */
|
||||
DM_EVENT_DEVICE_ERROR = 0x000200, /* Device failure. */
|
||||
DM_EVENT_PATH_ERROR = 0x000400, /* Failure on an io path. */
|
||||
DM_EVENT_ADAPTOR_ERROR = 0x000800, /* Failure off a host adaptor. */
|
||||
DM_EVENT_ADAPTOR_ERROR = 0x000800, /* Failure of a host adaptor. */
|
||||
|
||||
DM_EVENT_STATUS_MASK = 0xFF0000,
|
||||
DM_EVENT_SYNC_STATUS = 0x010000, /* Mirror synchronization completed/failed. */
|
||||
@@ -44,50 +47,60 @@ enum dm_event_type {
|
||||
|
||||
#define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK
|
||||
|
||||
/* Prototypes for event lib interface. */
|
||||
|
||||
struct dm_event_handler;
|
||||
|
||||
/* Create and destroy dm_event_handler struct, which is passed to
|
||||
register/unregister functions below */
|
||||
struct dm_event_handler *dm_event_handler_create(void);
|
||||
void dm_event_handler_destroy(struct dm_event_handler *h);
|
||||
void dm_event_handler_destroy(struct dm_event_handler *dmevh);
|
||||
|
||||
/* Set parameters of a handler:
|
||||
- dso - shared library path to handle the events
|
||||
(only one of the following three needs to be set)
|
||||
- name - device name or path
|
||||
- uuid - device uuid
|
||||
- major and minor - device major/minor numbers
|
||||
- events - a bitfield defining which events to handle (see
|
||||
enum dm_event_type above)
|
||||
*/
|
||||
void dm_event_handler_set_dso(struct dm_event_handler *h, const char *path);
|
||||
void dm_event_handler_set_name(struct dm_event_handler *h, const char *name);
|
||||
void dm_event_handler_set_uuid(struct dm_event_handler *h, const char *uuid);
|
||||
void dm_event_handler_set_major(struct dm_event_handler *h, int major);
|
||||
void dm_event_handler_set_minor(struct dm_event_handler *h, int minor);
|
||||
void dm_event_handler_set_events(struct dm_event_handler *h,
|
||||
enum dm_event_type event);
|
||||
/*
|
||||
* Path of shared library to handle events.
|
||||
*
|
||||
* All of dso, device_name and uuid strings are duplicated, you do not
|
||||
* need to keep the pointers valid after the call succeeds. Thes may
|
||||
* return -ENOMEM though.
|
||||
*/
|
||||
int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path);
|
||||
|
||||
/* Get parameters of a handler, same as above */
|
||||
const char *dm_event_handler_get_dso(const struct dm_event_handler *h);
|
||||
const char *dm_event_handler_get_name(const struct dm_event_handler *h);
|
||||
const char *dm_event_handler_get_uuid(const struct dm_event_handler *h);
|
||||
int dm_event_handler_get_major(const struct dm_event_handler *h);
|
||||
int dm_event_handler_get_minor(const struct dm_event_handler *h);
|
||||
enum dm_event_type dm_event_handler_get_events(const struct dm_event_handler *h);
|
||||
/*
|
||||
* Identify the device to monitor by exactly one of device_name, uuid or
|
||||
* device number. String arguments are duplicated, see above.
|
||||
*/
|
||||
int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *device_name);
|
||||
|
||||
/* Call out to dmeventd to register or unregister a handler. If
|
||||
dmeventd is not running, it is spawned first. */
|
||||
int dm_event_register(const struct dm_event_handler *h);
|
||||
int dm_event_unregister(const struct dm_event_handler *h);
|
||||
int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid);
|
||||
|
||||
void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major);
|
||||
void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor);
|
||||
void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout);
|
||||
|
||||
/*
|
||||
* Specify mask for events to monitor.
|
||||
*/
|
||||
void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh,
|
||||
enum dm_event_mask evmask);
|
||||
|
||||
const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh);
|
||||
const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh);
|
||||
const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh);
|
||||
int dm_event_handler_get_major(const struct dm_event_handler *dmevh);
|
||||
int dm_event_handler_get_minor(const struct dm_event_handler *dmevh);
|
||||
int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh);
|
||||
enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh);
|
||||
|
||||
/* FIXME Review interface (what about this next thing?) */
|
||||
int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next);
|
||||
|
||||
/*
|
||||
* Initiate monitoring using dmeventd.
|
||||
*/
|
||||
int dm_event_register_handler(const struct dm_event_handler *dmevh);
|
||||
int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
|
||||
|
||||
/* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
|
||||
detailed descriptions. */
|
||||
void process_event(struct dm_task *dmt, enum dm_event_type event);
|
||||
int register_device(const char *device, const char *uuid, int major, int minor);
|
||||
int unregister_device(const char *device, const char *uuid, int major,
|
||||
int minor);
|
||||
void process_event(struct dm_task *dmt, enum dm_event_mask evmask, void **user);
|
||||
int register_device(const char *device_name, const char *uuid, int major, int minor, void **user);
|
||||
int unregister_device(const char *device_name, const char *uuid, int major,
|
||||
int minor, void **user);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <libdevmapper.h>
|
||||
#include <libdevmapper-event.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
@@ -62,8 +61,12 @@ static int _get_mirror_event(char *params)
|
||||
int log_argc, num_devs;
|
||||
|
||||
/*
|
||||
* Unused: 0 409600 mirror
|
||||
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
|
||||
* dm core parms: 0 409600 mirror
|
||||
* Mirror core parms: 2 253:4 253:5 400/400
|
||||
* New-style failure params: 1 AA
|
||||
* New-style log params: 3 cluster 253:3 A
|
||||
* or 3 disk 253:3 A
|
||||
* or 1 core
|
||||
*/
|
||||
|
||||
/* number of devices */
|
||||
@@ -74,9 +77,9 @@ static int _get_mirror_event(char *params)
|
||||
goto out_parse;
|
||||
p += strlen(p) + 1;
|
||||
|
||||
/* devices names + max log parameters */
|
||||
args = dm_malloc((num_devs + 8) * sizeof(char *));
|
||||
if (!args || dm_split_words(p, num_devs + 8, 0, args) < num_devs + 8)
|
||||
/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
|
||||
args = dm_malloc((num_devs + 7) * sizeof(char *));
|
||||
if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
|
||||
goto out_parse;
|
||||
|
||||
dev_status_str = args[2 + num_devs];
|
||||
@@ -148,7 +151,7 @@ static int _remove_failed_devices(const char *device)
|
||||
}
|
||||
|
||||
/* FIXME Is any sanity-checking required on %s? */
|
||||
if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --removemissing %s", vg)) {
|
||||
if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --config devices{ignore_suspended_devices=1} --removemissing %s", vg)) {
|
||||
/* this error should be caught above, but doesn't hurt to check again */
|
||||
syslog(LOG_ERR, "Unable to form LVM command: Device name too long");
|
||||
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
|
||||
@@ -161,7 +164,8 @@ static int _remove_failed_devices(const char *device)
|
||||
return (r == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt, enum dm_event_type event)
|
||||
void process_event(struct dm_task *dmt, enum dm_event_mask event,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
@@ -218,7 +222,8 @@ void process_event(struct dm_task *dmt, enum dm_event_type event)
|
||||
pthread_mutex_unlock(&_event_mutex);
|
||||
}
|
||||
|
||||
int register_device(const char *device, const char *uuid, int major, int minor)
|
||||
int register_device(const char *device, const char *uuid, int major, int minor,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
@@ -254,7 +259,8 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device, const char *uuid, int major, int minor)
|
||||
int unregister_device(const char *device, const char *uuid, int major, int minor,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <libdevmapper.h>
|
||||
#include <libdevmapper-event.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
@@ -62,8 +61,12 @@ static int _get_mirror_event(char *params)
|
||||
int log_argc, num_devs;
|
||||
|
||||
/*
|
||||
* Unused: 0 409600 mirror
|
||||
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
|
||||
* dm core parms: 0 409600 mirror
|
||||
* Mirror core parms: 2 253:4 253:5 400/400
|
||||
* New-style failure params: 1 AA
|
||||
* New-style log params: 3 cluster 253:3 A
|
||||
* or 3 disk 253:3 A
|
||||
* or 1 core
|
||||
*/
|
||||
|
||||
/* number of devices */
|
||||
@@ -74,9 +77,9 @@ static int _get_mirror_event(char *params)
|
||||
goto out_parse;
|
||||
p += strlen(p) + 1;
|
||||
|
||||
/* devices names + max log parameters */
|
||||
args = dm_malloc((num_devs + 8) * sizeof(char *));
|
||||
if (!args || dm_split_words(p, num_devs + 8, 0, args) < num_devs + 8)
|
||||
/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
|
||||
args = dm_malloc((num_devs + 7) * sizeof(char *));
|
||||
if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
|
||||
goto out_parse;
|
||||
|
||||
dev_status_str = args[2 + num_devs];
|
||||
@@ -148,7 +151,7 @@ static int _remove_failed_devices(const char *device)
|
||||
}
|
||||
|
||||
/* FIXME Is any sanity-checking required on %s? */
|
||||
if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --removemissing %s", vg)) {
|
||||
if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --config devices{ignore_suspended_devices=1} --removemissing %s", vg)) {
|
||||
/* this error should be caught above, but doesn't hurt to check again */
|
||||
syslog(LOG_ERR, "Unable to form LVM command: Device name too long");
|
||||
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
|
||||
@@ -161,7 +164,8 @@ static int _remove_failed_devices(const char *device)
|
||||
return (r == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
void process_event(struct dm_task *dmt, enum dm_event_type event)
|
||||
void process_event(struct dm_task *dmt, enum dm_event_mask event,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
@@ -218,7 +222,8 @@ void process_event(struct dm_task *dmt, enum dm_event_type event)
|
||||
pthread_mutex_unlock(&_event_mutex);
|
||||
}
|
||||
|
||||
int register_device(const char *device, const char *uuid, int major, int minor)
|
||||
int register_device(const char *device, const char *uuid, int major, int minor,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
@@ -254,7 +259,8 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device, const char *uuid, int major, int minor)
|
||||
int unregister_device(const char *device, const char *uuid, int major, int minor,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
|
||||
@@ -19,6 +19,14 @@ devices {
|
||||
# to use with LVM2.
|
||||
scan = [ "/dev" ]
|
||||
|
||||
# If several entries in the scanned directories correspond to the
|
||||
# same block device and the tools need to display a name for device,
|
||||
# all the pathnames are matched against each item in the following
|
||||
# list of regular expressions in turn and the first match is used.
|
||||
preferred_names = [ ]
|
||||
|
||||
# preferred_names = [ "^/dev/mpath/", "^/dev/[hs]d" ]
|
||||
|
||||
# A filter that tells LVM2 to only use a restricted set of devices.
|
||||
# The filter consists of an array of regular expressions. These
|
||||
# expressions can be delimited by a character of your choice, and
|
||||
@@ -56,10 +64,14 @@ devices {
|
||||
# filter = [ "a|^/dev/hda8$|", "r/.*/" ]
|
||||
|
||||
# The results of the filtering are cached on disk to avoid
|
||||
# rescanning dud devices (which can take a very long time). By
|
||||
# default this cache file is hidden in the /etc/lvm directory.
|
||||
# It is safe to delete this file: the tools regenerate it.
|
||||
cache = "/etc/lvm/.cache"
|
||||
# rescanning dud devices (which can take a very long time).
|
||||
# By default this cache is stored in the /etc/lvm/cache directory
|
||||
# in a file called '.cache'.
|
||||
# It is safe to delete the contents: the tools regenerate it.
|
||||
# (The old setting 'cache' is still respected if neither of
|
||||
# these new ones is present.)
|
||||
cache_dir = "/etc/lvm/cache"
|
||||
cache_file_prefix = ""
|
||||
|
||||
# You can turn off writing this cache file by setting this to 0.
|
||||
write_cache_state = 1
|
||||
@@ -79,6 +91,12 @@ devices {
|
||||
# software RAID (md) devices by looking for md superblocks.
|
||||
# 1 enables; 0 disables.
|
||||
md_component_detection = 1
|
||||
|
||||
# If, while scanning the system for PVs, LVM2 encounters a device-mapper
|
||||
# device that has its I/O suspended, it waits for it to become accessible.
|
||||
# Set this to 1 to skip such devices. This should only be needed
|
||||
# in recovery situations.
|
||||
ignore_suspended_devices = 0
|
||||
}
|
||||
|
||||
# This section that allows you to configure the nature of the
|
||||
@@ -182,6 +200,9 @@ global {
|
||||
# command. Defaults to off.
|
||||
test = 0
|
||||
|
||||
# Default value for --units argument
|
||||
units = "h"
|
||||
|
||||
# Whether or not to communicate with the kernel device-mapper.
|
||||
# Set to 0 if you want to use the tools to manipulate LVM metadata
|
||||
# without activating any logical volumes.
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
../lib/misc/lvm-string.h
|
||||
../lib/misc/lvm-wrappers.h
|
||||
../lib/misc/sharedlib.h
|
||||
../lib/regex/matcher.h
|
||||
../lib/report/report.h
|
||||
../lib/uuid/uuid.h
|
||||
../po/pogen.h
|
||||
|
||||
@@ -81,9 +81,6 @@ SOURCES =\
|
||||
misc/lvm-wrappers.c \
|
||||
misc/timestamp.c \
|
||||
mm/memlock.c \
|
||||
regex/matcher.c \
|
||||
regex/parse_rx.c \
|
||||
regex/ttree.c \
|
||||
report/report.c \
|
||||
striped/striped.c \
|
||||
uuid/uuid.c \
|
||||
|
||||
@@ -168,6 +168,10 @@ int lvs_in_vg_activated(struct volume_group *vg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int lvs_in_vg_opened(struct volume_group *vg)
|
||||
{
|
||||
return 0;
|
||||
@@ -421,21 +425,23 @@ int target_present(const char *target_name, int use_modprobe)
|
||||
* Returns 1 if info structure populated, else 0 on failure.
|
||||
*/
|
||||
static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int with_mknodes,
|
||||
struct lvinfo *info, int with_open_count)
|
||||
struct lvinfo *info, int with_open_count, unsigned by_uuid_only)
|
||||
{
|
||||
struct dm_info dminfo;
|
||||
char *name;
|
||||
char *name = NULL;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
if (!(name = build_dm_name(cmd->mem, lv->vg->name, lv->name, NULL)))
|
||||
if (!by_uuid_only &&
|
||||
!(name = build_dm_name(cmd->mem, lv->vg->name, lv->name, NULL)))
|
||||
return_0;
|
||||
|
||||
log_debug("Getting device info for %s", name);
|
||||
if (!dev_manager_info(lv->vg->cmd->mem, name, lv, with_mknodes,
|
||||
with_open_count, &dminfo)) {
|
||||
dm_pool_free(cmd->mem, name);
|
||||
if (name)
|
||||
dm_pool_free(cmd->mem, name);
|
||||
return_0;
|
||||
}
|
||||
|
||||
@@ -448,14 +454,16 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv, in
|
||||
info->live_table = dminfo.live_table;
|
||||
info->inactive_table = dminfo.inactive_table;
|
||||
|
||||
dm_pool_free(cmd->mem, name);
|
||||
if (name)
|
||||
dm_pool_free(cmd->mem, name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, struct lvinfo *info,
|
||||
int with_open_count)
|
||||
{
|
||||
return _lv_info(cmd, lv, 0, info, with_open_count);
|
||||
return _lv_info(cmd, lv, 0, info, with_open_count, 0);
|
||||
}
|
||||
|
||||
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||
@@ -466,7 +474,7 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||
if (!(lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
return 0;
|
||||
|
||||
return _lv_info(cmd, lv, 0, info, with_open_count);
|
||||
return _lv_info(cmd, lv, 0, info, with_open_count, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -519,11 +527,12 @@ int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _lv_active(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
static int _lv_active(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
unsigned by_uuid_only)
|
||||
{
|
||||
struct lvinfo info;
|
||||
|
||||
if (!lv_info(cmd, lv, &info, 0)) {
|
||||
if (!_lv_info(cmd, lv, 0, &info, 0, by_uuid_only)) {
|
||||
stack;
|
||||
return -1;
|
||||
}
|
||||
@@ -607,7 +616,7 @@ static int _lv_suspend_lv(struct logical_volume *lv, int lockfs)
|
||||
* These two functions return the number of visible LVs in the state,
|
||||
* or -1 on error.
|
||||
*/
|
||||
int lvs_in_vg_activated(struct volume_group *vg)
|
||||
static int _lvs_in_vg_activated(struct volume_group *vg, unsigned by_uuid_only)
|
||||
{
|
||||
struct lv_list *lvl;
|
||||
int count = 0;
|
||||
@@ -617,12 +626,22 @@ int lvs_in_vg_activated(struct volume_group *vg)
|
||||
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if (lvl->lv->status & VISIBLE_LV)
|
||||
count += (_lv_active(vg->cmd, lvl->lv) == 1);
|
||||
count += (_lv_active(vg->cmd, lvl->lv, by_uuid_only) == 1);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg)
|
||||
{
|
||||
return _lvs_in_vg_activated(vg, 1);
|
||||
}
|
||||
|
||||
int lvs_in_vg_activated(struct volume_group *vg)
|
||||
{
|
||||
return _lvs_in_vg_activated(vg, 0);
|
||||
}
|
||||
|
||||
int lvs_in_vg_opened(struct volume_group *vg)
|
||||
{
|
||||
struct lv_list *lvl;
|
||||
@@ -640,50 +659,89 @@ int lvs_in_vg_opened(struct volume_group *vg)
|
||||
}
|
||||
|
||||
/*
|
||||
* register_dev_for_events
|
||||
*
|
||||
* This function uses proper error codes (but breaks convention)
|
||||
* to return:
|
||||
* -1 on error
|
||||
* 0 if the lv's targets don't do event [un]registration
|
||||
* 0 if the lv is already [un]registered -- FIXME: not implemented
|
||||
* 1 if the lv had a segment which was [un]registered
|
||||
*
|
||||
* Returns: -1 on error
|
||||
* Returns 0 if an attempt to (un)monitor the device failed.
|
||||
* Returns 1 otherwise.
|
||||
*/
|
||||
int register_dev_for_events(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int do_reg)
|
||||
int monitor_dev_for_events(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int monitor)
|
||||
{
|
||||
#ifdef DMEVENTD
|
||||
int r = 0;
|
||||
int i, pending = 0, monitored;
|
||||
int r = 1;
|
||||
struct list *tmp;
|
||||
struct lv_segment *seg;
|
||||
int (*reg) (struct lv_segment *, int events);
|
||||
int (*monitor_fn) (struct lv_segment *s, int e);
|
||||
|
||||
if (do_reg && !dmeventd_register_mode())
|
||||
/* skip dmeventd code altogether */
|
||||
if (dmeventd_monitor_mode() == DMEVENTD_MONITOR_IGNORE)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Nothing to do if dmeventd configured not to be used.
|
||||
*/
|
||||
if (monitor && !dmeventd_monitor_mode())
|
||||
return 1;
|
||||
|
||||
list_iterate(tmp, &lv->segments) {
|
||||
seg = list_item(tmp, struct lv_segment);
|
||||
|
||||
reg = NULL;
|
||||
|
||||
if (do_reg) {
|
||||
if (seg->segtype->ops->target_register_events)
|
||||
reg = seg->segtype->ops->target_register_events;
|
||||
} else if (seg->segtype->ops->target_unregister_events)
|
||||
reg = seg->segtype->ops->target_unregister_events;
|
||||
|
||||
if (!reg)
|
||||
if (!seg_monitored(seg) || (seg->status & PVMOVE))
|
||||
continue;
|
||||
|
||||
/* FIXME specify events */
|
||||
if (!reg(seg, 0)) {
|
||||
stack;
|
||||
return -1;
|
||||
monitor_fn = NULL;
|
||||
|
||||
/* Check monitoring status */
|
||||
if (seg->segtype->ops->target_monitored)
|
||||
monitored = seg->segtype->ops->target_monitored(seg, &pending);
|
||||
else
|
||||
continue; /* segtype doesn't support registration */
|
||||
|
||||
/*
|
||||
* FIXME: We should really try again if pending
|
||||
*/
|
||||
monitored = (pending) ? 0 : monitored;
|
||||
|
||||
if (monitor) {
|
||||
if (monitored)
|
||||
log_verbose("%s/%s already monitored.", lv->vg->name, lv->name);
|
||||
else if (seg->segtype->ops->target_monitor_events)
|
||||
monitor_fn = seg->segtype->ops->target_monitor_events;
|
||||
} else {
|
||||
if (!monitored)
|
||||
log_verbose("%s/%s already not monitored.", lv->vg->name, lv->name);
|
||||
else if (seg->segtype->ops->target_unmonitor_events)
|
||||
monitor_fn = seg->segtype->ops->target_unmonitor_events;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
/* Do [un]monitor */
|
||||
if (!monitor_fn)
|
||||
continue;
|
||||
|
||||
log_verbose("%sonitoring %s/%s", monitor ? "M" : "Not m", lv->vg->name, lv->name);
|
||||
|
||||
/* FIXME specify events */
|
||||
if (!monitor_fn(seg, 0)) {
|
||||
log_error("%s/%s: %s segment monitoring function failed.",
|
||||
lv->vg->name, lv->name, seg->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check [un]monitor results */
|
||||
/* Try a couple times if pending, but not forever... */
|
||||
for (i = 0; i < 10; i++) {
|
||||
pending = 0;
|
||||
monitored = seg->segtype->ops->target_monitored(seg, &pending);
|
||||
if (pending ||
|
||||
(!monitored && monitor) ||
|
||||
(monitored && !monitor))
|
||||
log_very_verbose("%s/%s %smonitoring still pending: waiting...",
|
||||
lv->vg->name, lv->name, monitor ? "" : "un");
|
||||
else
|
||||
break;
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
r = (monitored && monitor) || (!monitored && !monitor);
|
||||
}
|
||||
|
||||
return r;
|
||||
@@ -728,7 +786,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
}
|
||||
}
|
||||
|
||||
if (register_dev_for_events(cmd, lv, 0) != 1)
|
||||
if (!monitor_dev_for_events(cmd, lv, 0))
|
||||
/* FIXME Consider aborting here */
|
||||
stack;
|
||||
|
||||
@@ -786,7 +844,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
memlock_dec();
|
||||
fs_unlock();
|
||||
|
||||
if (register_dev_for_events(cmd, lv, 1) != 1)
|
||||
if (!monitor_dev_for_events(cmd, lv, 1))
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
@@ -832,7 +890,7 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (register_dev_for_events(cmd, lv, 0) != 1)
|
||||
if (!monitor_dev_for_events(cmd, lv, 0))
|
||||
stack;
|
||||
|
||||
memlock_inc();
|
||||
@@ -905,7 +963,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
memlock_dec();
|
||||
fs_unlock();
|
||||
|
||||
if (!register_dev_for_events(cmd, lv, 1) != 1)
|
||||
if (!monitor_dev_for_events(cmd, lv, 1))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
@@ -934,7 +992,7 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!_lv_info(cmd, lv, 1, &info, 0))
|
||||
if (!_lv_info(cmd, lv, 1, &info, 0, 0))
|
||||
return_0;
|
||||
|
||||
if (info.exists)
|
||||
|
||||
@@ -83,10 +83,11 @@ int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
* Return number of LVs in the VG that are active.
|
||||
*/
|
||||
int lvs_in_vg_activated(struct volume_group *vg);
|
||||
int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg);
|
||||
int lvs_in_vg_opened(struct volume_group *vg);
|
||||
|
||||
|
||||
int register_dev_for_events(struct cmd_context *cmd,
|
||||
int monitor_dev_for_events(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int do_reg);
|
||||
|
||||
/*
|
||||
@@ -95,4 +96,9 @@ int register_dev_for_events(struct cmd_context *cmd,
|
||||
int pv_uses_vg(struct physical_volume *pv,
|
||||
struct volume_group *vg);
|
||||
|
||||
/*
|
||||
* Returns 1 if mapped device is not suspended.
|
||||
*/
|
||||
int device_is_usable(dev_t dev);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "targets.h"
|
||||
#include "config.h"
|
||||
#include "filter.h"
|
||||
#include "activate.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
@@ -117,12 +118,10 @@ static struct dm_task *_setup_task(const char *name, const char *uuid,
|
||||
}
|
||||
|
||||
static int _info_run(const char *name, const char *dlid, struct dm_info *info,
|
||||
int mknodes, int with_open_count, struct dm_pool *mem,
|
||||
char **uuid_out)
|
||||
int mknodes, int with_open_count)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
const char *u;
|
||||
int dmtask;
|
||||
|
||||
dmtask = mknodes ? DM_DEVICE_MKNODES : DM_DEVICE_INFO;
|
||||
@@ -142,11 +141,58 @@ static int _info_run(const char *name, const char *dlid, struct dm_info *info,
|
||||
if (!dm_task_get_info(dmt, info))
|
||||
goto_out;
|
||||
|
||||
if (info->exists && uuid_out) {
|
||||
if (!(u = dm_task_get_uuid(dmt)))
|
||||
goto_out;
|
||||
*uuid_out = dm_pool_strdup(mem, u);
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
int device_is_usable(dev_t dev)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
struct dm_info info;
|
||||
const char *name;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
void *next = NULL;
|
||||
int r = 0;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
|
||||
log_error("Failed to allocate dm_task struct to check dev status");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_task_set_major(dmt, MAJOR(dev)) || !dm_task_set_minor(dmt, MINOR(dev)))
|
||||
goto_out;
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
log_error("Failed to get state of mapped device");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dm_task_get_info(dmt, &info))
|
||||
goto_out;
|
||||
|
||||
if (!info.exists || info.suspended)
|
||||
goto out;
|
||||
|
||||
name = dm_task_get_name(dmt);
|
||||
|
||||
/* FIXME Also check for mirror block_on_error and mpath no paths */
|
||||
/* For now, we exclude all mirrors */
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
/* Skip if target type doesn't match */
|
||||
if (!strcmp(target_type, "mirror"))
|
||||
goto out;
|
||||
} while (next);
|
||||
|
||||
/* FIXME Also check dependencies? */
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
@@ -155,23 +201,20 @@ static int _info_run(const char *name, const char *dlid, struct dm_info *info,
|
||||
}
|
||||
|
||||
static int _info(const char *name, const char *dlid, int mknodes,
|
||||
int with_open_count, struct dm_info *info,
|
||||
struct dm_pool *mem, char **uuid_out)
|
||||
int with_open_count, struct dm_info *info)
|
||||
{
|
||||
if (!mknodes && dlid && *dlid) {
|
||||
if (_info_run(NULL, dlid, info, 0, with_open_count, mem,
|
||||
uuid_out) &&
|
||||
if (_info_run(NULL, dlid, info, 0, with_open_count) &&
|
||||
info->exists)
|
||||
return 1;
|
||||
else if (_info_run(NULL, dlid + sizeof(UUID_PREFIX) - 1, info,
|
||||
0, with_open_count, mem, uuid_out) &&
|
||||
0, with_open_count) &&
|
||||
info->exists)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (name)
|
||||
return _info_run(name, NULL, info, mknodes, with_open_count,
|
||||
mem, uuid_out);
|
||||
return _info_run(name, NULL, info, mknodes, with_open_count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -187,8 +230,7 @@ int dev_manager_info(struct dm_pool *mem, const char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _info(name, dlid, with_mknodes, with_open_count, info,
|
||||
NULL, NULL);
|
||||
return _info(name, dlid, with_mknodes, with_open_count, info);
|
||||
}
|
||||
|
||||
/* FIXME Interface must cope with multiple targets */
|
||||
@@ -393,10 +435,8 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(dm = dm_pool_alloc(mem, sizeof(*dm)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(dm = dm_pool_alloc(mem, sizeof(*dm))))
|
||||
goto_bad;
|
||||
|
||||
dm->cmd = cmd;
|
||||
dm->mem = mem;
|
||||
@@ -408,10 +448,8 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
|
||||
}
|
||||
dm->stripe_filler = stripe_filler;
|
||||
|
||||
if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name)))
|
||||
goto_bad;
|
||||
|
||||
dm->target_state = NULL;
|
||||
|
||||
@@ -593,7 +631,7 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
return_0;
|
||||
|
||||
log_debug("Getting device info for %s [%s]", name, dlid);
|
||||
if (!_info(name, dlid, 0, 1, &info, dm->mem, NULL)) {
|
||||
if (!_info(name, dlid, 0, 1, &info)) {
|
||||
log_error("Failed to get info for %s [%s].", name, dlid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
12
lib/cache/lvmcache.c
vendored
12
lib/cache/lvmcache.c
vendored
@@ -135,7 +135,7 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
|
||||
|
||||
list_iterate_safe(devh, tmp, &devs) {
|
||||
devl = list_item(devh, struct device_list);
|
||||
label_read(devl->dev, &label);
|
||||
label_read(devl->dev, &label, UINT64_C(0));
|
||||
list_del(&devl->list);
|
||||
dm_free(devl);
|
||||
}
|
||||
@@ -205,7 +205,7 @@ static void _rescan_entry(struct lvmcache_info *info)
|
||||
struct label *label;
|
||||
|
||||
if (info->status & CACHE_INVALID)
|
||||
label_read(info->dev, &label);
|
||||
label_read(info->dev, &label, UINT64_C(0));
|
||||
}
|
||||
|
||||
static int _scan_invalid(void)
|
||||
@@ -247,7 +247,7 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
}
|
||||
|
||||
while ((dev = dev_iter_get(iter)))
|
||||
label_read(dev, &label);
|
||||
label_read(dev, &label, UINT64_C(0));
|
||||
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
@@ -346,7 +346,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
|
||||
/* Already cached ? */
|
||||
if ((info = info_from_pvid((char *) pvid))) {
|
||||
if (label_read(info->dev, &label)) {
|
||||
if (label_read(info->dev, &label, UINT64_C(0))) {
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||
return info->dev;
|
||||
@@ -357,7 +357,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
|
||||
/* Try again */
|
||||
if ((info = info_from_pvid((char *) pvid))) {
|
||||
if (label_read(info->dev, &label)) {
|
||||
if (label_read(info->dev, &label, UINT64_C(0))) {
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||
return info->dev;
|
||||
@@ -371,7 +371,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
|
||||
/* Try again */
|
||||
if ((info = info_from_pvid((char *) pvid))) {
|
||||
if (label_read(info->dev, &label)) {
|
||||
if (label_read(info->dev, &label, UINT64_C(0))) {
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||
return info->dev;
|
||||
|
||||
@@ -59,8 +59,6 @@
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
|
||||
static FILE *_log;
|
||||
|
||||
static int _get_env_vars(struct cmd_context *cmd)
|
||||
{
|
||||
const char *e;
|
||||
@@ -467,10 +465,8 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
const struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
|
||||
if (!dev_cache_init()) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!dev_cache_init(cmd))
|
||||
return_0;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, "devices/scan"))) {
|
||||
if (!dev_cache_add_dir("/dev")) {
|
||||
@@ -575,9 +571,9 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
|
||||
filters[0] : composite_filter_create(nr_filt, filters);
|
||||
}
|
||||
|
||||
static int _init_filters(struct cmd_context *cmd)
|
||||
static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
|
||||
{
|
||||
const char *dev_cache;
|
||||
const char *dev_cache = NULL, *cache_dir, *cache_file_prefix;
|
||||
struct dev_filter *f3, *f4;
|
||||
struct stat st;
|
||||
char cache_file[PATH_MAX];
|
||||
@@ -587,16 +583,35 @@ static int _init_filters(struct cmd_context *cmd)
|
||||
if (!(f3 = _init_filter_components(cmd)))
|
||||
return 0;
|
||||
|
||||
if (dm_snprintf(cache_file, sizeof(cache_file),
|
||||
"%s/.cache", cmd->sys_dir) < 0) {
|
||||
log_error("Persistent cache filename too long ('%s/.cache').",
|
||||
cmd->sys_dir);
|
||||
init_ignore_suspended_devices(find_config_tree_int(cmd,
|
||||
"devices/ignore_suspended_devices", DEFAULT_IGNORE_SUSPENDED_DEVICES));
|
||||
|
||||
/*
|
||||
* If 'cache_dir' or 'cache_file_prefix' is set, ignore 'cache'.
|
||||
*/
|
||||
cache_dir = find_config_tree_str(cmd, "devices/cache_dir", NULL);
|
||||
cache_file_prefix = find_config_tree_str(cmd, "devices/cache_file_prefix", NULL);
|
||||
|
||||
if (cache_dir || cache_file_prefix) {
|
||||
if (dm_snprintf(cache_file, sizeof(cache_file),
|
||||
"%s%s%s/%s.cache",
|
||||
cache_dir ? "" : cmd->sys_dir,
|
||||
cache_dir ? "" : "/",
|
||||
cache_dir ? : DEFAULT_CACHE_SUBDIR,
|
||||
cache_file_prefix ? : DEFAULT_CACHE_FILE_PREFIX) < 0) {
|
||||
log_error("Persistent cache filename too long.");
|
||||
return 0;
|
||||
}
|
||||
} else if (!(dev_cache = find_config_tree_str(cmd, "devices/cache", NULL)) &&
|
||||
(dm_snprintf(cache_file, sizeof(cache_file),
|
||||
"%s/%s/%s.cache",
|
||||
cmd->sys_dir, DEFAULT_CACHE_SUBDIR,
|
||||
DEFAULT_CACHE_FILE_PREFIX) < 0)) {
|
||||
log_error("Persistent cache filename too long.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_cache = find_config_tree_str(cmd, "devices/cache",
|
||||
cache_file);
|
||||
if (!(f4 = persistent_filter_create(f3, dev_cache))) {
|
||||
if (!(f4 = persistent_filter_create(f3, dev_cache ? : cache_file))) {
|
||||
log_error("Failed to create persistent device filter");
|
||||
return 0;
|
||||
}
|
||||
@@ -608,8 +623,13 @@ static int _init_filters(struct cmd_context *cmd)
|
||||
if (!*cmd->sys_dir)
|
||||
cmd->dump_filter = 0;
|
||||
|
||||
if (!stat(dev_cache, &st) &&
|
||||
(st.st_ctime != config_file_timestamp(cmd->cft)) &&
|
||||
/*
|
||||
* Only load persistent filter device cache on startup if it is newer
|
||||
* than the config file and this is not a long-lived process.
|
||||
*/
|
||||
if (load_persistent_cache && !cmd->is_long_lived &&
|
||||
!stat(dev_cache, &st) &&
|
||||
(st.st_ctime > config_file_timestamp(cmd->cft)) &&
|
||||
!persistent_filter_load(f4, NULL))
|
||||
log_verbose("Failed to load existing device cache from %s",
|
||||
dev_cache);
|
||||
@@ -748,7 +768,6 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
struct config_value *cv;
|
||||
struct segment_type *(*init_segtype_fn) (struct cmd_context *);
|
||||
void *lib;
|
||||
struct list *sgtl, *tmp;
|
||||
struct segment_type *segtype2;
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
@@ -775,18 +794,16 @@ static int _init_segtypes(struct cmd_context *cmd)
|
||||
segtype->library = lib;
|
||||
list_add(&cmd->segtypes, &segtype->list);
|
||||
|
||||
list_iterate_safe(sgtl, tmp, &cmd->segtypes) {
|
||||
segtype2 = list_item(sgtl, struct segment_type);
|
||||
if (!strcmp(segtype2->name, segtype->name)) {
|
||||
log_error("Duplicate segment type %s: "
|
||||
"unloading shared library %s",
|
||||
segtype->name, cv->v.str);
|
||||
list_del(&segtype->list);
|
||||
segtype->ops->destroy(segtype);
|
||||
dlclose(lib);
|
||||
break;
|
||||
}
|
||||
|
||||
list_iterate_items(segtype2, &cmd->segtypes) {
|
||||
if ((segtype == segtype2) ||
|
||||
strcmp(segtype2->name, segtype->name))
|
||||
continue;
|
||||
log_error("Duplicate segment type %s: "
|
||||
"unloading shared library %s",
|
||||
segtype->name, cv->v.str);
|
||||
list_del(&segtype->list);
|
||||
segtype->ops->destroy(segtype);
|
||||
dlclose(lib);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -881,7 +898,8 @@ static int _init_backup(struct cmd_context *cmd)
|
||||
}
|
||||
|
||||
/* Entry point */
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static)
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static,
|
||||
unsigned is_long_lived)
|
||||
{
|
||||
struct cmd_context *cmd;
|
||||
|
||||
@@ -905,6 +923,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static)
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->args = the_args;
|
||||
cmd->is_static = is_static;
|
||||
cmd->is_long_lived = is_long_lived;
|
||||
cmd->hosttags = 0;
|
||||
list_init(&cmd->formats);
|
||||
list_init(&cmd->segtypes);
|
||||
@@ -953,7 +972,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static)
|
||||
if (!_init_dev_cache(cmd))
|
||||
goto error;
|
||||
|
||||
if (!_init_filters(cmd))
|
||||
if (!_init_filters(cmd, 1))
|
||||
goto error;
|
||||
|
||||
if (!(cmd->mem = dm_pool_create("command", 4 * 1024))) {
|
||||
@@ -1022,10 +1041,10 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
{
|
||||
log_verbose("Reloading config files");
|
||||
|
||||
if (cmd->config_valid) {
|
||||
if (cmd->dump_filter)
|
||||
persistent_filter_dump(cmd->filter);
|
||||
}
|
||||
/*
|
||||
* Don't update the persistent filter cache as we will
|
||||
* perform a full rescan.
|
||||
*/
|
||||
|
||||
activation_release();
|
||||
lvmcache_destroy();
|
||||
@@ -1064,7 +1083,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
if (!_init_dev_cache(cmd))
|
||||
return 0;
|
||||
|
||||
if (!_init_filters(cmd))
|
||||
if (!_init_filters(cmd, 0))
|
||||
return 0;
|
||||
|
||||
if (!_init_formats(cmd))
|
||||
@@ -1073,6 +1092,13 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
if (!_init_segtypes(cmd))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If we are a long-lived process, write out the updated persistent
|
||||
* device cache for the benefit of short-lived processes.
|
||||
*/
|
||||
if (cmd->is_long_lived && cmd->dump_filter)
|
||||
persistent_filter_dump(cmd->filter);
|
||||
|
||||
cmd->config_valid = 1;
|
||||
return 1;
|
||||
}
|
||||
@@ -1100,8 +1126,4 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
||||
activation_exit();
|
||||
fin_log();
|
||||
fin_syslog();
|
||||
|
||||
if (_log)
|
||||
fclose(_log);
|
||||
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ struct cmd_context {
|
||||
struct arg *args;
|
||||
char **argv;
|
||||
unsigned is_static; /* Static binary? */
|
||||
unsigned is_long_lived; /* Optimises persistent_filter handling */
|
||||
|
||||
struct dev_filter *filter;
|
||||
int dump_filter; /* Dump filter when exiting? */
|
||||
@@ -88,7 +89,7 @@ struct cmd_context {
|
||||
char proc_dir[PATH_MAX];
|
||||
};
|
||||
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static);
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static, unsigned is_long_lived);
|
||||
void destroy_toolcontext(struct cmd_context *cmd);
|
||||
int refresh_toolcontext(struct cmd_context *cmd);
|
||||
int config_files_changed(struct cmd_context *cmd);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "device.h"
|
||||
#include "str_list.h"
|
||||
#include "toolcontext.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -26,6 +27,9 @@
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define SECTION_B_CHAR '{'
|
||||
#define SECTION_E_CHAR '}'
|
||||
|
||||
enum {
|
||||
TOK_INT,
|
||||
TOK_FLOAT,
|
||||
@@ -79,7 +83,8 @@ static const int sep = '/';
|
||||
|
||||
#define match(t) do {\
|
||||
if (!_match_aux(p, (t))) {\
|
||||
log_error("Parse error at byte %d (line %d): unexpected token", p->tb - p->fb + 1, p->line); \
|
||||
log_error("Parse error at byte %" PRIptrdiff_t " (line %d): unexpected token", \
|
||||
p->tb - p->fb + 1, p->line); \
|
||||
return 0;\
|
||||
} \
|
||||
} while(0);
|
||||
@@ -210,18 +215,10 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!dev_read(dev, (uint64_t) offset, size, buf)) {
|
||||
log_error("Read from %s failed", dev_name(dev));
|
||||
if (!dev_read_circular(dev, (uint64_t) offset, size,
|
||||
(uint64_t) offset2, size2, buf)) {
|
||||
goto out;
|
||||
}
|
||||
if (size2) {
|
||||
if (!dev_read(dev, (uint64_t) offset2, size2,
|
||||
buf + size)) {
|
||||
log_error("Circular read from %s failed",
|
||||
dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
p->fb = buf;
|
||||
}
|
||||
|
||||
@@ -360,7 +357,7 @@ static void _write_value(FILE *fp, struct config_value *v)
|
||||
break;
|
||||
|
||||
case CFG_INT:
|
||||
fprintf(fp, "%d", v->v.i);
|
||||
fprintf(fp, "%" PRId64, v->v.i);
|
||||
break;
|
||||
|
||||
case CFG_EMPTY_ARRAY:
|
||||
@@ -435,13 +432,13 @@ int write_config_file(struct config_tree *cft, const char *file,
|
||||
log_verbose("Dumping configuration to %s", file);
|
||||
if (!argc) {
|
||||
if (!_write_config(cft->root, 0, fp, 0)) {
|
||||
log_error("Failure while writing configuration");
|
||||
log_error("Failure while writing to %s", file);
|
||||
r = 0;
|
||||
}
|
||||
} else while (argc--) {
|
||||
if ((cn = find_config_node(cft->root, *argv))) {
|
||||
if (!_write_config(cn, 1, fp, 0)) {
|
||||
log_error("Failure while writing configuration");
|
||||
log_error("Failure while writing to %s", file);
|
||||
r = 0;
|
||||
}
|
||||
} else {
|
||||
@@ -451,8 +448,10 @@ int write_config_file(struct config_tree *cft, const char *file,
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (fp != stdout)
|
||||
fclose(fp);
|
||||
if ((fp != stdout) && fclose(fp)) {
|
||||
log_sys_error("fclose", file);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -480,7 +479,7 @@ static struct config_node *_file(struct parser *p)
|
||||
|
||||
static struct config_node *_section(struct parser *p)
|
||||
{
|
||||
/* IDENTIFIER '{' VALUE* '}' */
|
||||
/* IDENTIFIER SECTION_B_CHAR VALUE* SECTION_E_CHAR */
|
||||
struct config_node *root, *n, *l = NULL;
|
||||
if (!(root = _create_node(p))) {
|
||||
stack;
|
||||
@@ -569,7 +568,7 @@ static struct config_value *_type(struct parser *p)
|
||||
switch (p->t) {
|
||||
case TOK_INT:
|
||||
v->type = CFG_INT;
|
||||
v->v.i = strtol(p->tb, NULL, 0); /* FIXME: check error */
|
||||
v->v.i = strtoll(p->tb, NULL, 0); /* FIXME: check error */
|
||||
match(TOK_INT);
|
||||
break;
|
||||
|
||||
@@ -592,7 +591,8 @@ static struct config_value *_type(struct parser *p)
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Parse error at byte %d (line %d): expected a value", p->tb - p->fb + 1, p->line);
|
||||
log_error("Parse error at byte %" PRIptrdiff_t " (line %d): expected a value",
|
||||
p->tb - p->fb + 1, p->line);
|
||||
return 0;
|
||||
}
|
||||
return v;
|
||||
@@ -629,12 +629,12 @@ static void _get_token(struct parser *p, int tok_prev)
|
||||
p->t = TOK_INT; /* fudge so the fall through for
|
||||
floats works */
|
||||
switch (*p->te) {
|
||||
case '{':
|
||||
case SECTION_B_CHAR:
|
||||
p->t = TOK_SECTION_B;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '}':
|
||||
case SECTION_E_CHAR:
|
||||
p->t = TOK_SECTION_E;
|
||||
p->te++;
|
||||
break;
|
||||
@@ -714,8 +714,9 @@ static void _get_token(struct parser *p, int tok_prev)
|
||||
default:
|
||||
p->t = TOK_IDENTIFIER;
|
||||
while ((p->te != p->fe) && (*p->te) && !isspace(*p->te) &&
|
||||
(*p->te != '#') && (*p->te != '=') && (*p->te != '{') &&
|
||||
(*p->te != '}'))
|
||||
(*p->te != '#') && (*p->te != '=') &&
|
||||
(*p->te != SECTION_B_CHAR) &&
|
||||
(*p->te != SECTION_E_CHAR))
|
||||
p->te++;
|
||||
break;
|
||||
}
|
||||
@@ -853,7 +854,7 @@ static const char *_find_config_str(const struct config_node *cn1,
|
||||
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
|
||||
|
||||
/* Empty strings are ignored */
|
||||
if ((n && n->v->type == CFG_STRING) && (*n->v->v.str)) {
|
||||
if ((n && n->v && n->v->type == CFG_STRING) && (*n->v->v.str)) {
|
||||
log_very_verbose("Setting %s to %s", path, n->v->v.str);
|
||||
return n->v->v.str;
|
||||
}
|
||||
@@ -870,25 +871,26 @@ const char *find_config_str(const struct config_node *cn,
|
||||
return _find_config_str(cn, NULL, path, fail);
|
||||
}
|
||||
|
||||
static int _find_config_int(const struct config_node *cn1,
|
||||
const struct config_node *cn2,
|
||||
const char *path, int fail)
|
||||
static int64_t _find_config_int64(const struct config_node *cn1,
|
||||
const struct config_node *cn2,
|
||||
const char *path, int64_t fail)
|
||||
{
|
||||
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
|
||||
|
||||
if (n && n->v->type == CFG_INT) {
|
||||
log_very_verbose("Setting %s to %d", path, n->v->v.i);
|
||||
if (n && n->v && n->v->type == CFG_INT) {
|
||||
log_very_verbose("Setting %s to %" PRId64, path, n->v->v.i);
|
||||
return n->v->v.i;
|
||||
}
|
||||
|
||||
log_very_verbose("%s not found in config: defaulting to %d",
|
||||
log_very_verbose("%s not found in config: defaulting to %" PRId64,
|
||||
path, fail);
|
||||
return fail;
|
||||
}
|
||||
|
||||
int find_config_int(const struct config_node *cn, const char *path, int fail)
|
||||
{
|
||||
return _find_config_int(cn, NULL, path, fail);
|
||||
/* FIXME Add log_error message on overflow */
|
||||
return (int) _find_config_int64(cn, NULL, path, (int64_t) fail);
|
||||
}
|
||||
|
||||
static float _find_config_float(const struct config_node *cn1,
|
||||
@@ -897,7 +899,7 @@ static float _find_config_float(const struct config_node *cn1,
|
||||
{
|
||||
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
|
||||
|
||||
if (n && n->v->type == CFG_FLOAT) {
|
||||
if (n && n->v && n->v->type == CFG_FLOAT) {
|
||||
log_very_verbose("Setting %s to %f", path, n->v->v.r);
|
||||
return n->v->v.r;
|
||||
}
|
||||
@@ -930,7 +932,8 @@ const char *find_config_tree_str(struct cmd_context *cmd,
|
||||
int find_config_tree_int(struct cmd_context *cmd, const char *path,
|
||||
int fail)
|
||||
{
|
||||
return _find_config_int(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
|
||||
/* FIXME Add log_error message on overflow */
|
||||
return (int) _find_config_int64(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, (int64_t) fail);
|
||||
}
|
||||
|
||||
float find_config_tree_float(struct cmd_context *cmd, const char *path,
|
||||
@@ -1022,7 +1025,6 @@ int get_config_uint64(const struct config_node *cn, const char *path,
|
||||
if (!n || !n->v || n->v->type != CFG_INT)
|
||||
return 0;
|
||||
|
||||
/* FIXME Support 64-bit value! */
|
||||
*result = (uint64_t) n->v->v.i;
|
||||
return 1;
|
||||
}
|
||||
@@ -1152,3 +1154,61 @@ int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a token type to the char it represents.
|
||||
*/
|
||||
static char _token_type_to_char(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case TOK_SECTION_B:
|
||||
return SECTION_B_CHAR;
|
||||
case TOK_SECTION_E:
|
||||
return SECTION_E_CHAR;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* # of 'type' tokens in 'str'.
|
||||
*/
|
||||
static unsigned _count_tokens (const char *str, unsigned len, int type)
|
||||
{
|
||||
char c;
|
||||
|
||||
c = _token_type_to_char(type);
|
||||
|
||||
return(count_chars_len(str, len, c));
|
||||
}
|
||||
|
||||
/*
|
||||
* Heuristic function to make a quick guess as to whether a text
|
||||
* region probably contains a valid config "section". (Useful for
|
||||
* scanning areas of the disk for old metadata.)
|
||||
* Config sections contain various tokens, may contain other sections
|
||||
* and strings, and are delimited by begin (type 'TOK_SECTION_B') and
|
||||
* end (type 'TOK_SECTION_E') tokens. As a quick heuristic, we just
|
||||
* count the number of begin and end tokens, and see if they are
|
||||
* non-zero and the counts match.
|
||||
* Full validation of the section should be done with another function
|
||||
* (for example, read_config_fd).
|
||||
*
|
||||
* Returns:
|
||||
* 0 - probably is not a valid config section
|
||||
* 1 - probably _is_ a valid config section
|
||||
*/
|
||||
unsigned maybe_config_section(const char *str, unsigned len)
|
||||
{
|
||||
int begin_count;
|
||||
int end_count;
|
||||
|
||||
begin_count = _count_tokens(str, len, TOK_SECTION_B);
|
||||
end_count = _count_tokens(str, len, TOK_SECTION_E);
|
||||
|
||||
if (begin_count && end_count && (begin_count - end_count == 0))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ enum {
|
||||
struct config_value {
|
||||
int type;
|
||||
union {
|
||||
int i;
|
||||
int64_t i;
|
||||
float r;
|
||||
char *str;
|
||||
} v;
|
||||
@@ -108,4 +108,6 @@ int get_config_uint64(const struct config_node *cn, const char *path,
|
||||
int get_config_str(const struct config_node *cn, const char *path,
|
||||
char **result);
|
||||
|
||||
unsigned maybe_config_section(const char *str, unsigned len);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#define DEFAULT_ARCHIVE_SUBDIR "archive"
|
||||
#define DEFAULT_BACKUP_SUBDIR "backup"
|
||||
#define DEFAULT_CACHE_SUBDIR "cache"
|
||||
#define DEFAULT_CACHE_FILE_PREFIX ""
|
||||
|
||||
#define DEFAULT_ARCHIVE_DAYS 30
|
||||
#define DEFAULT_ARCHIVE_NUMBER 10
|
||||
@@ -30,6 +32,7 @@
|
||||
#define DEFAULT_PROC_DIR "/proc"
|
||||
#define DEFAULT_SYSFS_SCAN 1
|
||||
#define DEFAULT_MD_COMPONENT_DETECTION 1
|
||||
#define DEFAULT_IGNORE_SUSPENDED_DEVICES 1
|
||||
|
||||
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
|
||||
#define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so"
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
/* Define some portable printing types */
|
||||
#define PRIsize_t "zu"
|
||||
#define PRIptrdiff_t "td"
|
||||
|
||||
struct str_list {
|
||||
struct list list;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "btree.h"
|
||||
#include "filter.h"
|
||||
#include "filter-persistent.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
@@ -38,6 +39,7 @@ static struct {
|
||||
struct dm_pool *mem;
|
||||
struct dm_hash_table *names;
|
||||
struct btree *devices;
|
||||
struct dm_regex *preferred_names_matcher;
|
||||
|
||||
int has_scanned;
|
||||
struct list dirs;
|
||||
@@ -129,15 +131,52 @@ static struct device *_dev_create(dev_t d)
|
||||
return dev;
|
||||
}
|
||||
|
||||
void dev_set_preferred_name(struct str_list *sl, struct device *dev)
|
||||
{
|
||||
/*
|
||||
* Don't interfere with ordering specified in config file.
|
||||
*/
|
||||
if (_cache.preferred_names_matcher)
|
||||
return;
|
||||
|
||||
log_debug("%s: New preferred name", sl->str);
|
||||
list_del(&sl->list);
|
||||
list_add_h(&dev->aliases, &sl->list);
|
||||
}
|
||||
|
||||
/* Return 1 if we prefer path1 else return 0 */
|
||||
static int _compare_paths(const char *path0, const char *path1)
|
||||
{
|
||||
int slash0 = 0, slash1 = 0;
|
||||
int m0, m1;
|
||||
const char *p;
|
||||
char p0[PATH_MAX], p1[PATH_MAX];
|
||||
char *s0, *s1;
|
||||
struct stat stat0, stat1;
|
||||
|
||||
/*
|
||||
* FIXME Better to compare patterns one-at-a-time against all names.
|
||||
*/
|
||||
if (_cache.preferred_names_matcher) {
|
||||
m0 = dm_regex_match(_cache.preferred_names_matcher, path0);
|
||||
m1 = dm_regex_match(_cache.preferred_names_matcher, path1);
|
||||
|
||||
if (m0 != m1) {
|
||||
if (m0 < 0)
|
||||
return 1;
|
||||
if (m1 < 0)
|
||||
return 0;
|
||||
if (m0 < m1)
|
||||
return 1;
|
||||
if (m1 < m0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Built-in rules.
|
||||
*/
|
||||
|
||||
/* Return the path with fewer slashes */
|
||||
for (p = path0; p++; p = (const char *) strchr(p, '/'))
|
||||
slash0++;
|
||||
@@ -441,7 +480,65 @@ void dev_cache_scan(int do_scan)
|
||||
_full_scan(1);
|
||||
}
|
||||
|
||||
int dev_cache_init(void)
|
||||
static int _init_preferred_names(struct cmd_context *cmd)
|
||||
{
|
||||
const struct config_node *cn;
|
||||
struct config_value *v;
|
||||
struct dm_pool *scratch = NULL;
|
||||
char **regex;
|
||||
unsigned count = 0;
|
||||
int i, r = 0;
|
||||
|
||||
_cache.preferred_names_matcher = NULL;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, "devices/preferred_names")) ||
|
||||
cn->v->type == CFG_EMPTY_ARRAY) {
|
||||
log_very_verbose("devices/preferred_names not found in config file: "
|
||||
"using built-in preferences");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (v = cn->v; v; v = v->next) {
|
||||
if (v->type != CFG_STRING) {
|
||||
log_error("preferred_names patterns must be enclosed in quotes");
|
||||
return 0;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!(scratch = dm_pool_create("preferred device name matcher", 1024)))
|
||||
return_0;
|
||||
|
||||
if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) {
|
||||
log_error("Failed to allocate preferred device name "
|
||||
"pattern list.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (v = cn->v, i = count - 1; v; v = v->next, i--) {
|
||||
if (!(regex[i] = dm_pool_strdup(scratch, v->v.str))) {
|
||||
log_error("Failed to allocate a preferred device name "
|
||||
"pattern.");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(_cache.preferred_names_matcher =
|
||||
dm_regex_create(_cache.mem,(const char **) regex, count))) {
|
||||
log_error("Preferred device name pattern matcher creation failed.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
dm_pool_destroy(scratch);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dev_cache_init(struct cmd_context *cmd)
|
||||
{
|
||||
_cache.names = NULL;
|
||||
_cache.has_scanned = 0;
|
||||
@@ -466,6 +563,9 @@ int dev_cache_init(void)
|
||||
list_init(&_cache.dirs);
|
||||
list_init(&_cache.files);
|
||||
|
||||
if (!_init_preferred_names(cmd))
|
||||
goto_bad;
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
@@ -489,6 +589,9 @@ void dev_cache_exit(void)
|
||||
if (_cache.names)
|
||||
_check_for_open_devices();
|
||||
|
||||
if (_cache.preferred_names_matcher)
|
||||
_cache.preferred_names_matcher = NULL;
|
||||
|
||||
if (_cache.mem) {
|
||||
dm_pool_destroy(_cache.mem);
|
||||
_cache.mem = NULL;
|
||||
|
||||
@@ -30,7 +30,8 @@ struct dev_filter {
|
||||
/*
|
||||
* The global device cache.
|
||||
*/
|
||||
int dev_cache_init(void);
|
||||
struct cmd_context;
|
||||
int dev_cache_init(struct cmd_context *cmd);
|
||||
void dev_cache_exit(void);
|
||||
|
||||
/* Trigger(1) or avoid(0) a scan */
|
||||
@@ -41,6 +42,8 @@ int dev_cache_add_dir(const char *path);
|
||||
int dev_cache_add_loopfile(const char *path);
|
||||
struct device *dev_cache_get(const char *name, struct dev_filter *f);
|
||||
|
||||
void dev_set_preferred_name(struct str_list *sl, struct device *dev);
|
||||
|
||||
/*
|
||||
* Object for iterating through the cache.
|
||||
*/
|
||||
|
||||
@@ -292,11 +292,14 @@ int dev_get_sectsize(struct device *dev, uint32_t *size)
|
||||
|
||||
if (ioctl(fd, BLKSSZGET, &s) < 0) {
|
||||
log_sys_error("ioctl BLKSSZGET", name);
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("close", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("close", name);
|
||||
|
||||
*size = (uint32_t) s;
|
||||
|
||||
log_very_verbose("%s: sector size is %" PRIu32 " bytes", name, *size);
|
||||
@@ -561,6 +564,35 @@ int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer)
|
||||
return _aligned_io(&where, buffer, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from 'dev' into 'buf', possibly in 2 distinct regions, denoted
|
||||
* by (offset,len) and (offset2,len2). Thus, the total size of
|
||||
* 'buf' should be len+len2.
|
||||
*/
|
||||
int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
|
||||
uint64_t offset2, size_t len2, void *buf)
|
||||
{
|
||||
if (!dev_read(dev, offset, len, buf)) {
|
||||
log_error("Read from %s failed", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The second region is optional, and allows for
|
||||
* a circular buffer on the device.
|
||||
*/
|
||||
if (!len2)
|
||||
return 1;
|
||||
|
||||
if (!dev_read(dev, offset2, len2, buf + len)) {
|
||||
log_error("Circular read from %s failed",
|
||||
dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME If O_DIRECT can't extend file, dev_extend first; dev_truncate after.
|
||||
* But fails if concurrent processes writing
|
||||
*/
|
||||
|
||||
@@ -53,8 +53,10 @@ int dev_is_md(struct device *dev, uint64_t *sb)
|
||||
sb_offset = MD_NEW_SIZE_SECTORS(size) << SECTOR_SHIFT;
|
||||
|
||||
/* Check if it is an md component device. */
|
||||
/* Version 1 is little endian; version 0.90.0 is machine endian */
|
||||
if (dev_read(dev, sb_offset, sizeof(uint32_t), &md_magic) &&
|
||||
(md_magic == xlate32(MD_SB_MAGIC))) {
|
||||
((md_magic == xlate32(MD_SB_MAGIC)) ||
|
||||
(md_magic == MD_SB_MAGIC))) {
|
||||
if (sb)
|
||||
*sb = sb_offset;
|
||||
ret = 1;
|
||||
|
||||
@@ -72,7 +72,7 @@ static int _has_partition_table(struct device *dev)
|
||||
/* Check for msdos partition table */
|
||||
part_magic = buf + PART_MAGIC_OFFSET/sizeof(buf[0]);
|
||||
if ((*part_magic == xlate16(PART_MAGIC))) {
|
||||
part = (struct partition *) (buf + PART_OFFSET);
|
||||
part = (struct partition *) (buf + PART_OFFSET/sizeof(buf[0]));
|
||||
for (p = 0; p < 4; p++, part++) {
|
||||
/* Table is invalid if boot indicator not 0 or 0x80 */
|
||||
if ((part->boot_ind & 0x7f)) {
|
||||
|
||||
@@ -78,6 +78,8 @@ int dev_fd(struct device *dev);
|
||||
const char *dev_name(const struct device *dev);
|
||||
|
||||
int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer);
|
||||
int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
|
||||
uint64_t offset2, size_t len2, void *buf);
|
||||
int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer);
|
||||
int dev_append(struct device *dev, size_t len, void *buffer);
|
||||
int dev_set(struct device *dev, uint64_t offset, size_t len, int value);
|
||||
|
||||
@@ -239,7 +239,10 @@ int persistent_filter_dump(struct dev_filter *f)
|
||||
/* _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); */
|
||||
|
||||
fprintf(fp, "}\n");
|
||||
fclose(fp);
|
||||
if (fclose(fp)) {
|
||||
log_sys_error("fclose", tmp_file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rename(tmp_file, pf->file))
|
||||
log_error("%s: rename to %s failed: %s", tmp_file, pf->file,
|
||||
@@ -298,10 +301,9 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
|
||||
}
|
||||
memset(pf, 0, sizeof(*pf));
|
||||
|
||||
if (!(pf->file = dm_malloc(strlen(file) + 1))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(pf->file = dm_malloc(strlen(file) + 1)))
|
||||
goto_bad;
|
||||
|
||||
strcpy(pf->file, file);
|
||||
pf->real = real;
|
||||
|
||||
@@ -310,10 +312,8 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(f = dm_malloc(sizeof(*f)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(f = dm_malloc(sizeof(*f))))
|
||||
goto_bad;
|
||||
|
||||
f->passes_filter = _lookup_p;
|
||||
f->destroy = _persistent_destroy;
|
||||
|
||||
@@ -15,13 +15,12 @@
|
||||
|
||||
#include "lib.h"
|
||||
#include "filter-regex.h"
|
||||
#include "matcher.h"
|
||||
#include "device.h"
|
||||
|
||||
struct rfilter {
|
||||
struct dm_pool *mem;
|
||||
dm_bitset_t accept;
|
||||
struct matcher *engine;
|
||||
struct dm_regex *engine;
|
||||
};
|
||||
|
||||
static int _extract_pattern(struct dm_pool *mem, const char *pat,
|
||||
@@ -98,18 +97,15 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
unsigned count = 0;
|
||||
int i, r = 0;
|
||||
|
||||
if (!(scratch = dm_pool_create("filter matcher", 1024))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!(scratch = dm_pool_create("filter dm_regex", 1024)))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* count how many patterns we have.
|
||||
*/
|
||||
for (v = val; v; v = v->next) {
|
||||
|
||||
if (v->type != CFG_STRING) {
|
||||
log_info("filter patterns must be enclosed in quotes");
|
||||
log_error("filter patterns must be enclosed in quotes");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -119,10 +115,8 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
/*
|
||||
* allocate space for them
|
||||
*/
|
||||
if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count)))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* create the accept/reject bitset
|
||||
@@ -136,15 +130,15 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
*/
|
||||
for (v = val, i = count - 1; v; v = v->next, i--)
|
||||
if (!_extract_pattern(scratch, v->v.str, regex, rf->accept, i)) {
|
||||
log_info("invalid filter pattern");
|
||||
log_error("invalid filter pattern");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* build the matcher.
|
||||
*/
|
||||
if (!(rf->engine = matcher_create(rf->mem, (const char **) regex,
|
||||
count)))
|
||||
if (!(rf->engine = dm_regex_create(rf->mem, (const char **) regex,
|
||||
count)))
|
||||
stack;
|
||||
r = 1;
|
||||
|
||||
@@ -160,17 +154,12 @@ static int _accept_p(struct dev_filter *f, struct device *dev)
|
||||
struct str_list *sl;
|
||||
|
||||
list_iterate_items(sl, &dev->aliases) {
|
||||
m = matcher_run(rf->engine, sl->str);
|
||||
m = dm_regex_match(rf->engine, sl->str);
|
||||
|
||||
if (m >= 0) {
|
||||
if (dm_bit(rf->accept, m)) {
|
||||
|
||||
if (!first) {
|
||||
log_debug("%s: New preferred name",
|
||||
sl->str);
|
||||
list_del(&sl->list);
|
||||
list_add_h(&dev->aliases, &sl->list);
|
||||
}
|
||||
if (!first)
|
||||
dev_set_preferred_name(sl, dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -208,22 +197,16 @@ struct dev_filter *regex_filter_create(struct config_value *patterns)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(rf = dm_pool_alloc(mem, sizeof(*rf)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(rf = dm_pool_alloc(mem, sizeof(*rf))))
|
||||
goto_bad;
|
||||
|
||||
rf->mem = mem;
|
||||
|
||||
if (!_build_matcher(rf, patterns)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!_build_matcher(rf, patterns))
|
||||
goto_bad;
|
||||
|
||||
if (!(f = dm_pool_zalloc(mem, sizeof(*f)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(f = dm_pool_zalloc(mem, sizeof(*f))))
|
||||
goto_bad;
|
||||
|
||||
f->passes_filter = _accept_p;
|
||||
f->destroy = _regex_destroy;
|
||||
|
||||
@@ -54,7 +54,9 @@ static int _locate_sysfs_blocks(const char *proc, char *path, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", proc_mounts);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -156,7 +158,9 @@ static int _read_dev(const char *file, dev_t *result)
|
||||
}
|
||||
|
||||
r = _parse_dev(file, fp, result);
|
||||
fclose(fp);
|
||||
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", file);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -280,10 +284,8 @@ struct dev_filter *sysfs_filter_create(const char *proc)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(f = dm_pool_zalloc(mem, sizeof(*f)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(f = dm_pool_zalloc(mem, sizeof(*f))))
|
||||
goto_bad;
|
||||
|
||||
f->passes_filter = _accept_p;
|
||||
f->destroy = _destroy;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "lvm-string.h"
|
||||
#include "config.h"
|
||||
#include "metadata.h"
|
||||
#include "activate.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
@@ -37,6 +38,7 @@ typedef struct {
|
||||
} device_info_t;
|
||||
|
||||
static int _md_major = -1;
|
||||
static int _device_mapper_major = -1;
|
||||
|
||||
int md_major(void)
|
||||
{
|
||||
@@ -90,6 +92,13 @@ static int _passes_lvm_type_device_filter(struct dev_filter *f,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Skip suspended devices */
|
||||
if (MAJOR(dev->dev) == _device_mapper_major &&
|
||||
ignore_suspended_devices() && !device_is_usable(dev->dev)) {
|
||||
log_debug("%s: Skipping: Suspended dm device", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check it's accessible */
|
||||
if (!dev_open_flags(dev, O_RDONLY, 0, 1)) {
|
||||
log_debug("%s: Skipping: open failed", name);
|
||||
@@ -182,10 +191,14 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2)))
|
||||
_md_major = line_maj;
|
||||
|
||||
/* Look for device-mapper device */
|
||||
/* FIXME Cope with multiple majors */
|
||||
if (!strncmp("device-mapper", line + i, 13) && isspace(*(line + i + 13)))
|
||||
_device_mapper_major = line_maj;
|
||||
|
||||
/* Go through the valid device names and if there is a
|
||||
match store max number of partitions */
|
||||
for (j = 0; device_info[j].name != NULL; j++) {
|
||||
|
||||
dev_len = strlen(device_info[j].name);
|
||||
if (dev_len <= strlen(line + i) &&
|
||||
!strncmp(device_info[j].name, line + i, dev_len) &&
|
||||
@@ -204,7 +217,8 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_error("Expecting string in devices/types "
|
||||
"in config file");
|
||||
fclose(pd);
|
||||
if (fclose(pd))
|
||||
log_sys_error("fclose", proc_devices);
|
||||
return 0;
|
||||
}
|
||||
dev_len = strlen(cv->v.str);
|
||||
@@ -214,14 +228,16 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
log_error("Max partition count missing for %s "
|
||||
"in devices/types in config file",
|
||||
name);
|
||||
fclose(pd);
|
||||
if (fclose(pd))
|
||||
log_sys_error("fclose", proc_devices);
|
||||
return 0;
|
||||
}
|
||||
if (!cv->v.i) {
|
||||
log_error("Zero partition count invalid for "
|
||||
"%s in devices/types in config file",
|
||||
name);
|
||||
fclose(pd);
|
||||
if (fclose(pd))
|
||||
log_sys_error("fclose", proc_devices);
|
||||
return 0;
|
||||
}
|
||||
if (dev_len <= strlen(line + i) &&
|
||||
@@ -232,7 +248,10 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(pd);
|
||||
|
||||
if (fclose(pd))
|
||||
log_sys_error("fclose", proc_devices);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -357,10 +357,8 @@ static struct disk_list *__read_disk(const struct format_type *fmt,
|
||||
list_init(&dl->uuids);
|
||||
list_init(&dl->lvds);
|
||||
|
||||
if (!_read_pvd(dev, &dl->pvd)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!_read_pvd(dev, &dl->pvd))
|
||||
goto_bad;
|
||||
|
||||
/*
|
||||
* is it an orphan ?
|
||||
|
||||
@@ -131,10 +131,10 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
||||
int partial;
|
||||
|
||||
if (!vg)
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (list_empty(pvs))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
memset(vg, 0, sizeof(*vg));
|
||||
|
||||
@@ -146,24 +146,24 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
||||
list_init(&vg->tags);
|
||||
|
||||
if (!_check_vgs(pvs, &partial))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
dl = list_item(pvs->n, struct disk_list);
|
||||
|
||||
if (!import_vg(mem, vg, dl, partial))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (!import_pvs(fid->fmt, mem, vg, pvs, &vg->pvs, &vg->pv_count))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (!import_lvs(mem, vg, pvs))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (!import_extents(fid->fmt->cmd, vg, pvs))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (!import_snapshots(mem, vg, pvs))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
return vg;
|
||||
|
||||
@@ -191,15 +191,11 @@ static struct volume_group *_format1_vg_read(struct format_instance *fid,
|
||||
vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
|
||||
|
||||
if (!read_pvs_in_vg
|
||||
(fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
(fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs))
|
||||
goto_bad;
|
||||
|
||||
if (!(vg = _build_vg(fid, &pvs))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(vg = _build_vg(fid, &pvs)))
|
||||
goto_bad;
|
||||
|
||||
bad:
|
||||
dm_pool_destroy(mem);
|
||||
@@ -415,17 +411,14 @@ static int _format1_pv_write(const struct format_type *fmt, struct physical_volu
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(dl = dm_pool_alloc(mem, sizeof(*dl)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(dl = dm_pool_alloc(mem, sizeof(*dl))))
|
||||
goto_bad;
|
||||
|
||||
dl->mem = mem;
|
||||
dl->dev = pv->dev;
|
||||
|
||||
if (!export_pv(fmt->cmd, mem, NULL, &dl->pvd, pv)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!export_pv(fmt->cmd, mem, NULL, &dl->pvd, pv))
|
||||
goto_bad;
|
||||
|
||||
/* must be set to be able to zero gap after PV structure in
|
||||
dev_write in order to make other disk tools happy */
|
||||
@@ -434,10 +427,8 @@ static int _format1_pv_write(const struct format_type *fmt, struct physical_volu
|
||||
dl->pvd.pe_on_disk.base = LVM1_PE_ALIGN << SECTOR_SHIFT;
|
||||
|
||||
list_add(&pvs, &dl->list);
|
||||
if (!write_disks(fmt, &pvs)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!write_disks(fmt, &pvs))
|
||||
goto_bad;
|
||||
|
||||
dm_pool_destroy(mem);
|
||||
return 1;
|
||||
|
||||
@@ -59,22 +59,16 @@ static struct dm_hash_table *_create_lv_maps(struct dm_pool *mem,
|
||||
if (ll->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
if (!(lvm = dm_pool_alloc(mem, sizeof(*lvm)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(lvm = dm_pool_alloc(mem, sizeof(*lvm))))
|
||||
goto_bad;
|
||||
|
||||
lvm->lv = ll->lv;
|
||||
if (!(lvm->map = dm_pool_zalloc(mem, sizeof(*lvm->map)
|
||||
* ll->lv->le_count))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
* ll->lv->le_count)))
|
||||
goto_bad;
|
||||
|
||||
if (!dm_hash_insert(maps, ll->lv->name, lvm)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!dm_hash_insert(maps, ll->lv->name, lvm))
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
return maps;
|
||||
@@ -203,6 +197,19 @@ static int _check_maps_are_complete(struct dm_hash_table *maps)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t _area_length(struct lv_map *lvm, uint32_t le)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
|
||||
do
|
||||
len++;
|
||||
while ((lvm->map[le + len].pv == lvm->map[le].pv) &&
|
||||
(lvm->map[le].pv &&
|
||||
lvm->map[le + len].pe == lvm->map[le].pe + len));
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
{
|
||||
uint32_t le = 0, len;
|
||||
@@ -215,13 +222,7 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
}
|
||||
|
||||
while (le < lvm->lv->le_count) {
|
||||
len = 0;
|
||||
|
||||
do
|
||||
len++;
|
||||
while ((lvm->map[le + len].pv == lvm->map[le].pv) &&
|
||||
(lvm->map[le].pv &&
|
||||
lvm->map[le + len].pe == lvm->map[le].pe + len));
|
||||
len = _area_length(lvm, le);
|
||||
|
||||
if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le,
|
||||
len, 0, 0, NULL, 1, len, 0, 0, 0))) {
|
||||
@@ -230,10 +231,8 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
}
|
||||
|
||||
if (!set_lv_segment_area_pv(seg, 0, lvm->map[le].pv,
|
||||
lvm->map[le].pe)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
lvm->map[le].pe))
|
||||
return_0;
|
||||
|
||||
list_add(&lvm->lv->segments, &seg->list);
|
||||
|
||||
@@ -244,7 +243,8 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
}
|
||||
|
||||
static int _check_stripe(struct lv_map *lvm, uint32_t area_count,
|
||||
uint32_t seg_len, uint32_t base_le, uint32_t len)
|
||||
uint32_t area_len, uint32_t base_le,
|
||||
uint32_t total_area_len)
|
||||
{
|
||||
uint32_t st;
|
||||
|
||||
@@ -252,11 +252,11 @@ static int _check_stripe(struct lv_map *lvm, uint32_t area_count,
|
||||
* Is the next physical extent in every stripe adjacent to the last?
|
||||
*/
|
||||
for (st = 0; st < area_count; st++)
|
||||
if ((lvm->map[base_le + st * len + seg_len].pv !=
|
||||
lvm->map[base_le + st * len].pv) ||
|
||||
(lvm->map[base_le + st * len].pv &&
|
||||
lvm->map[base_le + st * len + seg_len].pe !=
|
||||
lvm->map[base_le + st * len].pe + seg_len))
|
||||
if ((lvm->map[base_le + st * total_area_len + area_len].pv !=
|
||||
lvm->map[base_le + st * total_area_len].pv) ||
|
||||
(lvm->map[base_le + st * total_area_len].pv &&
|
||||
lvm->map[base_le + st * total_area_len + area_len].pe !=
|
||||
lvm->map[base_le + st * total_area_len].pe + area_len))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -264,7 +264,7 @@ static int _check_stripe(struct lv_map *lvm, uint32_t area_count,
|
||||
|
||||
static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
{
|
||||
uint32_t st, le = 0, len;
|
||||
uint32_t st, first_area_le = 0, total_area_len;
|
||||
uint32_t area_len;
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
@@ -277,26 +277,25 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
"with logical extent count (%u) for %s",
|
||||
lvm->stripes, lvm->lv->le_count, lvm->lv->name);
|
||||
}
|
||||
len = lvm->lv->le_count / lvm->stripes;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
total_area_len = lvm->lv->le_count / lvm->stripes;
|
||||
|
||||
while (le < len) {
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped")))
|
||||
return_0;
|
||||
|
||||
while (first_area_le < total_area_len) {
|
||||
area_len = 1;
|
||||
|
||||
/*
|
||||
* Find how many blocks are contiguous in all stripes
|
||||
* Find how many extents are contiguous in all stripes
|
||||
* and so can form part of this segment
|
||||
*/
|
||||
while (_check_stripe(lvm, lvm->stripes,
|
||||
area_len * lvm->stripes, le, len))
|
||||
area_len, first_area_le, total_area_len))
|
||||
area_len++;
|
||||
|
||||
if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv,
|
||||
lvm->stripes * le,
|
||||
lvm->stripes * first_area_le,
|
||||
lvm->stripes * area_len,
|
||||
0, lvm->stripe_size, NULL,
|
||||
lvm->stripes,
|
||||
@@ -310,15 +309,13 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
*/
|
||||
for (st = 0; st < seg->area_count; st++)
|
||||
if (!set_lv_segment_area_pv(seg, st,
|
||||
lvm->map[le + st * len].pv,
|
||||
lvm->map[le + st * len].pe)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
lvm->map[first_area_le + st * total_area_len].pv,
|
||||
lvm->map[first_area_le + st * total_area_len].pe))
|
||||
return_0;
|
||||
|
||||
list_add(&lvm->lv->segments, &seg->list);
|
||||
|
||||
le += seg->len;
|
||||
first_area_le += area_len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -249,17 +249,23 @@ int archive_vg(struct volume_group *vg,
|
||||
|
||||
if (!(fp = fdopen(fd, "w"))) {
|
||||
log_err("Couldn't create FILE object for archive.");
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("close", temp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!text_vg_export_file(vg, desc, fp)) {
|
||||
stack;
|
||||
fclose(fp);
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", temp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
if (fclose(fp)) {
|
||||
log_sys_error("fclose", temp_file);
|
||||
/* Leave file behind as evidence of failure */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we want to rename this file to <vg>_index.vg.
|
||||
|
||||
@@ -160,7 +160,7 @@ static int _out_with_comment_file(struct formatter *f, const char *comment,
|
||||
for (i = 0; i < f->indent; i++)
|
||||
white_space[i] = '\t';
|
||||
white_space[i] = '\0';
|
||||
fprintf(f->data.fp, white_space);
|
||||
fputs(white_space, f->data.fp);
|
||||
i = vfprintf(f->data.fp, fmt, ap);
|
||||
|
||||
if (comment) {
|
||||
@@ -176,7 +176,7 @@ static int _out_with_comment_file(struct formatter *f, const char *comment,
|
||||
|
||||
while (++i < COMMENT_TAB);
|
||||
|
||||
fprintf(f->data.fp, comment);
|
||||
fputs(comment, f->data.fp);
|
||||
}
|
||||
fputc('\n', f->data.fp);
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
#define FMT_TEXT_NAME "lvm2"
|
||||
#define FMT_TEXT_ALIAS "text"
|
||||
|
||||
static struct mda_header *_raw_read_mda_header(const struct format_type *fmt,
|
||||
struct device_area *dev_area);
|
||||
|
||||
static struct format_instance *_text_create_text_instance(const struct format_type
|
||||
*fmt, const char *vgname,
|
||||
const char *vgid,
|
||||
@@ -80,6 +83,164 @@ static int _text_vg_setup(struct format_instance *fid __attribute((unused)),
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if metadata area belongs to vg
|
||||
*/
|
||||
static int _mda_in_vg_raw(struct format_instance *fid __attribute((unused)),
|
||||
struct volume_group *vg, struct metadata_area *mda)
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs)
|
||||
if (pvl->pv->dev == mdac->area.dev)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For circular region between region_start and region_start + region_size,
|
||||
* back up one SECTOR_SIZE from 'region_ptr' and return the value.
|
||||
* This allows reverse traversal through text metadata area to find old
|
||||
* metadata.
|
||||
*
|
||||
* Parameters:
|
||||
* region_start: start of the region (bytes)
|
||||
* region_size: size of the region (bytes)
|
||||
* region_ptr: pointer within the region (bytes)
|
||||
* NOTE: region_start <= region_ptr <= region_start + region_size
|
||||
*/
|
||||
static uint64_t _get_prev_sector_circular(uint64_t region_start,
|
||||
uint64_t region_size,
|
||||
uint64_t region_ptr)
|
||||
{
|
||||
if (region_ptr >= region_start + SECTOR_SIZE)
|
||||
return region_ptr - SECTOR_SIZE;
|
||||
else
|
||||
return (region_start + region_size - SECTOR_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyze a metadata area for old metadata records in the circular buffer.
|
||||
* This function just looks through and makes a first pass at the data in
|
||||
* the sectors for particular things.
|
||||
* FIXME: do something with each metadata area (try to extract vg, write
|
||||
* raw data to file, etc)
|
||||
*/
|
||||
static int _pv_analyze_mda_raw (const struct format_type * fmt,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct mda_header *mdah;
|
||||
struct raw_locn *rlocn;
|
||||
uint64_t area_start;
|
||||
uint64_t area_size;
|
||||
uint64_t prev_sector;
|
||||
uint64_t latest_mrec_offset;
|
||||
int i;
|
||||
uint64_t offset;
|
||||
uint64_t offset2;
|
||||
uint64_t size;
|
||||
uint64_t size2;
|
||||
char *buf=NULL;
|
||||
struct device_area *area;
|
||||
struct mda_context *mdac;
|
||||
int r=0;
|
||||
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
|
||||
log_print("Found text metadata area, offset=%"PRIu64", size=%"PRIu64,
|
||||
mdac->area.start,
|
||||
mdac->area.size);
|
||||
area = &mdac->area;
|
||||
|
||||
if (!dev_open(area->dev))
|
||||
return_0;
|
||||
|
||||
if (!(mdah = _raw_read_mda_header(fmt, area)))
|
||||
goto_out;
|
||||
|
||||
rlocn = mdah->raw_locns;
|
||||
|
||||
/*
|
||||
* The device area includes the metadata header as well as the
|
||||
* records, so remove the metadata header from the start and size
|
||||
*/
|
||||
area_start = area->start + MDA_HEADER_SIZE;
|
||||
area_size = area->size - MDA_HEADER_SIZE;
|
||||
latest_mrec_offset = rlocn->offset + area->start;
|
||||
|
||||
/*
|
||||
* Start searching at rlocn (point of live metadata) and go
|
||||
* backwards.
|
||||
*/
|
||||
prev_sector = _get_prev_sector_circular(area_start, area_size,
|
||||
latest_mrec_offset);
|
||||
offset = prev_sector;
|
||||
size = SECTOR_SIZE;
|
||||
offset2 = size2 = 0;
|
||||
i = 0;
|
||||
while (prev_sector != latest_mrec_offset) {
|
||||
prev_sector = _get_prev_sector_circular(area_start, area_size,
|
||||
prev_sector);
|
||||
/*
|
||||
* FIXME: for some reason, the whole metadata region from
|
||||
* area->start to area->start+area->size is not used.
|
||||
* Only ~32KB seems to contain valid metadata records
|
||||
* (LVM2 format - format_text). As a result, I end up with
|
||||
* "maybe_config_section" returning true when there's no valid
|
||||
* metadata in a sector (sectors with all nulls).
|
||||
*/
|
||||
if (!(buf = dm_pool_alloc(fmt->cmd->mem, size + size2)))
|
||||
goto_out;
|
||||
|
||||
if (!dev_read_circular(area->dev, offset, size,
|
||||
offset2, size2, buf))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* FIXME: We could add more sophisticated metadata detection
|
||||
*/
|
||||
if (maybe_config_section(buf, size+size2)) {
|
||||
/* FIXME: Validate region, pull out timestamp?, etc */
|
||||
/* FIXME: Do something with this region */
|
||||
log_verbose ("Found LVM2 metadata record at "
|
||||
"offset=%"PRIu64", size=%"PRIu64", "
|
||||
"offset2=%"PRIu64" size2=%"PRIu64,
|
||||
offset, size, offset2, size2);
|
||||
offset = prev_sector;
|
||||
size = SECTOR_SIZE;
|
||||
offset2 = size2 = 0;
|
||||
} else {
|
||||
/*
|
||||
* Not a complete metadata record, assume we have
|
||||
* metadata and just increase the size and offset.
|
||||
* Start the second region if the previous sector is
|
||||
* wrapping around towards the end of the disk.
|
||||
*/
|
||||
if (prev_sector > offset) {
|
||||
offset2 = prev_sector;
|
||||
size2 += SECTOR_SIZE;
|
||||
} else {
|
||||
offset = prev_sector;
|
||||
size += SECTOR_SIZE;
|
||||
}
|
||||
}
|
||||
dm_pool_free(fmt->cmd->mem, buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
if (buf)
|
||||
dm_pool_free(fmt->cmd->mem, buf);
|
||||
if (!dev_close(area->dev))
|
||||
stack;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int _text_lv_setup(struct format_instance *fid __attribute((unused)),
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
@@ -710,7 +871,8 @@ static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
|
||||
|
||||
if (!(fp = fdopen(fd, "w"))) {
|
||||
log_sys_error("fdopen", temp_file);
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("fclose", temp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -718,13 +880,15 @@ static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
|
||||
|
||||
if (!text_vg_export_file(vg, tc->desc, fp)) {
|
||||
log_error("Failed to write metadata to %s.", temp_file);
|
||||
fclose(fp);
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", temp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fsync(fd) && (errno != EROFS) && (errno != EINVAL)) {
|
||||
log_sys_error("fsync", tc->path_edit);
|
||||
fclose(fp);
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", tc->path_edit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1268,7 +1432,7 @@ static int _text_pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
}
|
||||
|
||||
/* FIXME Optimise out repeated reading when cache lock held */
|
||||
if (!(label_read(dev, &label))) {
|
||||
if (!(label_read(dev, &label, UINT64_C(0)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1392,7 +1556,9 @@ static struct metadata_area_ops _metadata_text_raw_ops = {
|
||||
.vg_remove = _vg_remove_raw,
|
||||
.vg_precommit = _vg_precommit_raw,
|
||||
.vg_commit = _vg_commit_raw,
|
||||
.vg_revert = _vg_revert_raw
|
||||
.vg_revert = _vg_revert_raw,
|
||||
.mda_in_vg = _mda_in_vg_raw,
|
||||
.pv_analyze_mda = _pv_analyze_mda_raw,
|
||||
};
|
||||
|
||||
/* pvmetadatasize in sectors */
|
||||
|
||||
@@ -660,15 +660,11 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
/* eg Set to instance of fmt1 here if reading a format1 backup? */
|
||||
vg->fid = fid;
|
||||
|
||||
if (!(vg->name = dm_pool_strdup(mem, vgn->key))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(vg->name = dm_pool_strdup(mem, vgn->key)))
|
||||
goto_bad;
|
||||
|
||||
if (!(vg->system_id = dm_pool_zalloc(mem, NAME_LEN))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(vg->system_id = dm_pool_zalloc(mem, NAME_LEN)))
|
||||
goto_bad;
|
||||
|
||||
vgn = vgn->child;
|
||||
|
||||
|
||||
@@ -107,7 +107,8 @@ struct labeller *label_get_handler(const char *name)
|
||||
}
|
||||
|
||||
static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
uint64_t *label_sector)
|
||||
uint64_t *label_sector,
|
||||
uint64_t scan_sector)
|
||||
{
|
||||
struct labeller_i *li;
|
||||
struct labeller *r = NULL;
|
||||
@@ -117,12 +118,13 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
int found = 0;
|
||||
char readbuf[LABEL_SCAN_SIZE] __attribute((aligned(8)));
|
||||
|
||||
if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
|
||||
if (!dev_read(dev, scan_sector << SECTOR_SHIFT,
|
||||
LABEL_SCAN_SIZE, readbuf)) {
|
||||
log_debug("%s: Failed to read label area", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Scan first few sectors for a valid label */
|
||||
/* Scan a few sectors for a valid label */
|
||||
for (sector = 0; sector < LABEL_SCAN_SECTORS;
|
||||
sector += LABEL_SIZE >> SECTOR_SHIFT) {
|
||||
lh = (struct label_header *) (readbuf +
|
||||
@@ -132,13 +134,14 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
if (found) {
|
||||
log_error("Ignoring additional label on %s at "
|
||||
"sector %" PRIu64, dev_name(dev),
|
||||
sector);
|
||||
sector + scan_sector);
|
||||
}
|
||||
if (xlate64(lh->sector_xl) != sector) {
|
||||
if (xlate64(lh->sector_xl) != sector + scan_sector) {
|
||||
log_info("%s: Label for sector %" PRIu64
|
||||
" found at sector %" PRIu64
|
||||
" - ignoring", dev_name(dev),
|
||||
xlate64(lh->sector_xl), sector);
|
||||
xlate64(lh->sector_xl),
|
||||
sector + scan_sector);
|
||||
continue;
|
||||
}
|
||||
if (calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
|
||||
@@ -153,19 +156,21 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
}
|
||||
|
||||
list_iterate_items(li, &_labellers) {
|
||||
if (li->l->ops->can_handle(li->l, (char *) lh, sector)) {
|
||||
if (li->l->ops->can_handle(li->l, (char *) lh,
|
||||
sector + scan_sector)) {
|
||||
log_very_verbose("%s: %s label detected",
|
||||
dev_name(dev), li->name);
|
||||
if (found) {
|
||||
log_error("Ignoring additional label "
|
||||
"on %s at sector %" PRIu64,
|
||||
dev_name(dev), sector);
|
||||
dev_name(dev),
|
||||
sector + scan_sector);
|
||||
continue;
|
||||
}
|
||||
r = li->l;
|
||||
memcpy(buf, lh, LABEL_SIZE);
|
||||
if (label_sector)
|
||||
*label_sector = sector;
|
||||
*label_sector = sector + scan_sector;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
@@ -256,7 +261,8 @@ int label_remove(struct device *dev)
|
||||
}
|
||||
|
||||
/* FIXME Avoid repeated re-reading if cache lock held */
|
||||
int label_read(struct device *dev, struct label **result)
|
||||
int label_read(struct device *dev, struct label **result,
|
||||
uint64_t scan_sector)
|
||||
{
|
||||
char buf[LABEL_SIZE] __attribute((aligned(8)));
|
||||
struct labeller *l;
|
||||
@@ -274,7 +280,7 @@ int label_read(struct device *dev, struct label **result)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!(l = _find_labeller(dev, buf, §or)))
|
||||
if (!(l = _find_labeller(dev, buf, §or, scan_sector)))
|
||||
goto_out;
|
||||
|
||||
if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result)
|
||||
@@ -354,7 +360,7 @@ int label_verify(struct device *dev)
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!(l = _find_labeller(dev, buf, §or)))
|
||||
if (!(l = _find_labeller(dev, buf, §or, UINT64_C(0))))
|
||||
goto_out;
|
||||
|
||||
r = l->ops->verify ? l->ops->verify(l, buf, sector) : 1;
|
||||
|
||||
@@ -96,7 +96,8 @@ int label_register_handler(const char *name, struct labeller *handler);
|
||||
struct labeller *label_get_handler(const char *name);
|
||||
|
||||
int label_remove(struct device *dev);
|
||||
int label_read(struct device *dev, struct label **result);
|
||||
int label_read(struct device *dev, struct label **result,
|
||||
uint64_t scan_sector);
|
||||
int label_write(struct device *dev, struct label *label);
|
||||
int label_verify(struct device *dev);
|
||||
struct label *label_create(struct labeller *labeller);
|
||||
|
||||
@@ -321,8 +321,8 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
|
||||
if (mirror_in_sync())
|
||||
args[1] |= LCK_MIRROR_NOSYNC_MODE;
|
||||
|
||||
if (dmeventd_register_mode())
|
||||
args[1] |= LCK_DMEVENTD_REGISTER_MODE;
|
||||
if (dmeventd_monitor_mode())
|
||||
args[1] |= LCK_DMEVENTD_MONITOR_MODE;
|
||||
|
||||
/*
|
||||
* VG locks are just that: locks, and have no side effects
|
||||
|
||||
@@ -163,8 +163,8 @@ static int _lock_file(const char *file, int flags)
|
||||
log_very_verbose("Locking %s %c%c", ll->res, state,
|
||||
flags & LCK_NONBLOCK ? ' ' : 'B');
|
||||
do {
|
||||
if (ll->lf > -1)
|
||||
close(ll->lf);
|
||||
if ((ll->lf > -1) && close(ll->lf))
|
||||
log_sys_error("close", file);
|
||||
|
||||
if ((ll->lf = open(file, O_CREAT | O_APPEND | O_RDWR, 0777))
|
||||
< 0) {
|
||||
|
||||
@@ -75,7 +75,7 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
|
||||
*/
|
||||
#define LCK_PARTIAL_MODE 0x00000001 /* Running in partial mode */
|
||||
#define LCK_MIRROR_NOSYNC_MODE 0x00000002 /* Mirrors don't require sync */
|
||||
#define LCK_DMEVENTD_REGISTER_MODE 0x00000004 /* Register with dmeventd */
|
||||
#define LCK_DMEVENTD_MONITOR_MODE 0x00000004 /* Register with dmeventd */
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -81,7 +81,7 @@ int init_no_locking(struct locking_type *locking, struct cmd_context *cmd)
|
||||
locking->lock_resource = _no_lock_resource;
|
||||
locking->reset_locking = _no_reset_locking;
|
||||
locking->fin_locking = _no_fin_locking;
|
||||
locking->flags = 0;
|
||||
locking->flags = LCK_CLUSTERED;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@ static char _cmd_name[30] = "";
|
||||
static char _msg_prefix[30] = " ";
|
||||
static int _already_logging = 0;
|
||||
static int _mirror_in_sync = 0;
|
||||
static int _dmeventd_register = DEFAULT_DMEVENTD_MONITOR;
|
||||
static int _dmeventd_monitor = DEFAULT_DMEVENTD_MONITOR;
|
||||
static int _ignore_suspended_devices = 0;
|
||||
|
||||
static lvm2_log_fn_t _lvm2_log_fn = NULL;
|
||||
|
||||
@@ -120,7 +121,8 @@ void fin_log(void)
|
||||
}
|
||||
|
||||
if (_log_to_file) {
|
||||
fclose(_log_file);
|
||||
if (fclose(_log_file))
|
||||
fprintf(stderr, "fclose() on log file failed: %s", strerror(errno));
|
||||
_log_to_file = 0;
|
||||
}
|
||||
}
|
||||
@@ -189,9 +191,14 @@ void init_mirror_in_sync(int in_sync)
|
||||
_mirror_in_sync = in_sync;
|
||||
}
|
||||
|
||||
void init_dmeventd_register(int reg)
|
||||
void init_dmeventd_monitor(int reg)
|
||||
{
|
||||
_dmeventd_register = reg;
|
||||
_dmeventd_monitor = reg;
|
||||
}
|
||||
|
||||
void init_ignore_suspended_devices(int ignore)
|
||||
{
|
||||
_ignore_suspended_devices = ignore;
|
||||
}
|
||||
|
||||
void init_cmd_name(int status)
|
||||
@@ -268,9 +275,14 @@ int mirror_in_sync(void)
|
||||
return _mirror_in_sync;
|
||||
}
|
||||
|
||||
int dmeventd_register_mode(void)
|
||||
int dmeventd_monitor_mode(void)
|
||||
{
|
||||
return _dmeventd_register;
|
||||
return _dmeventd_monitor;
|
||||
}
|
||||
|
||||
int ignore_suspended_devices(void)
|
||||
{
|
||||
return _ignore_suspended_devices;
|
||||
}
|
||||
|
||||
void init_debug(int level)
|
||||
|
||||
@@ -75,7 +75,8 @@ void init_ignorelockingfailure(int level);
|
||||
void init_lockingfailed(int level);
|
||||
void init_security_level(int level);
|
||||
void init_mirror_in_sync(int in_sync);
|
||||
void init_dmeventd_register(int reg);
|
||||
void init_dmeventd_monitor(int reg);
|
||||
void init_ignore_suspended_devices(int ignore);
|
||||
|
||||
void set_cmd_name(const char *cmd_name);
|
||||
|
||||
@@ -90,7 +91,10 @@ int ignorelockingfailure(void);
|
||||
int lockingfailed(void);
|
||||
int security_level(void);
|
||||
int mirror_in_sync(void);
|
||||
int dmeventd_register_mode(void);
|
||||
int ignore_suspended_devices(void);
|
||||
|
||||
#define DMEVENTD_MONITOR_IGNORE -1
|
||||
int dmeventd_monitor_mode(void);
|
||||
|
||||
/* Suppress messages to stdout/stderr (1) or everywhere (2) */
|
||||
/* Returns previous setting */
|
||||
@@ -134,5 +138,6 @@ void print_log(int level, const char *file, int line, const char *format, ...)
|
||||
#define return_0 do { stack; return 0; } while (0)
|
||||
#define return_NULL do { stack; return NULL; } while (0)
|
||||
#define goto_out do { stack; goto out; } while (0)
|
||||
#define goto_bad do { stack; goto bad; } while (0)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -280,10 +280,9 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
vg->seqno = 0;
|
||||
|
||||
vg->status = (RESIZEABLE_VG | LVM_READ | LVM_WRITE);
|
||||
if (!(vg->system_id = dm_pool_alloc(mem, NAME_LEN))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(vg->system_id = dm_pool_alloc(mem, NAME_LEN)))
|
||||
goto_bad;
|
||||
|
||||
*vg->system_id = '\0';
|
||||
|
||||
vg->extent_size = extent_size;
|
||||
@@ -320,7 +319,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
|
||||
/* attach the pv's */
|
||||
if (!vg_extend(vg->fid, vg, pv_count, pv_names))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
return vg;
|
||||
|
||||
@@ -505,6 +504,34 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vg_split_mdas(struct cmd_context *cmd, struct volume_group *vg_from,
|
||||
struct volume_group *vg_to)
|
||||
{
|
||||
struct metadata_area *mda, *mda2;
|
||||
struct list *mdas_from, *mdas_to;
|
||||
int common_mda = 0;
|
||||
|
||||
mdas_from = &vg_from->fid->metadata_areas;
|
||||
mdas_to = &vg_to->fid->metadata_areas;
|
||||
|
||||
list_iterate_items_safe(mda, mda2, mdas_from) {
|
||||
if (!mda->ops->mda_in_vg) {
|
||||
common_mda = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!mda->ops->mda_in_vg(vg_from->fid, vg_from, mda)) {
|
||||
list_del(&mda->list);
|
||||
list_add(mdas_to, &mda->list);
|
||||
}
|
||||
}
|
||||
|
||||
if (list_empty(mdas_from) || list_empty(mdas_to))
|
||||
return common_mda;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Sizes in sectors */
|
||||
struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
@@ -533,10 +560,8 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
|
||||
pv->dev = dev;
|
||||
|
||||
if (!(pv->vg_name = dm_pool_zalloc(mem, NAME_LEN))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(pv->vg_name = dm_pool_zalloc(mem, NAME_LEN)))
|
||||
goto_bad;
|
||||
|
||||
pv->status = ALLOCATABLE_PV;
|
||||
|
||||
@@ -759,6 +784,12 @@ int vg_validate(struct volume_group *vg)
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(pvl->pv->vg_name, vg->name)) {
|
||||
log_error("Internal error: VG name for PV %s is corrupted",
|
||||
dev_name(pvl->pv->dev));
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!check_pv_segments(vg)) {
|
||||
@@ -963,6 +994,30 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
return vg;
|
||||
}
|
||||
|
||||
static int _update_pv_list(struct list *all_pvs, struct volume_group *vg)
|
||||
{
|
||||
struct pv_list *pvl, *pvl2;
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
list_iterate_items(pvl2, all_pvs) {
|
||||
if (pvl->pv->dev == pvl2->pv->dev)
|
||||
goto next_pv;
|
||||
}
|
||||
/* PV is not on list so add it. Note that we don't copy it. */
|
||||
if (!(pvl2 = dm_pool_zalloc(vg->cmd->mem, sizeof(*pvl2)))) {
|
||||
log_error("pv_list allocation for '%s' failed",
|
||||
dev_name(pvl->pv->dev));
|
||||
return 0;
|
||||
}
|
||||
pvl2->pv = pvl->pv;
|
||||
list_add(all_pvs, &pvl2->list);
|
||||
next_pv:
|
||||
;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Caller sets consistent to 1 if it's safe for vg_read to correct
|
||||
* inconsistent metadata on disk (i.e. the VG write lock is held).
|
||||
* This guarantees only consistent metadata is returned unless PARTIAL_VG.
|
||||
@@ -982,9 +1037,12 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
struct volume_group *vg, *correct_vg = NULL;
|
||||
struct metadata_area *mda;
|
||||
int inconsistent = 0;
|
||||
int inconsistent_vgid = 0;
|
||||
int use_precommitted = precommitted;
|
||||
struct list *pvids;
|
||||
struct pv_list *pvl;
|
||||
struct pv_list *pvl, *pvl2;
|
||||
struct list all_pvs;
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (!*vgname) {
|
||||
if (use_precommitted) {
|
||||
@@ -1069,6 +1127,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
list_init(&all_pvs);
|
||||
|
||||
/* Failed to find VG where we expected it - full scan and retry */
|
||||
if (!correct_vg) {
|
||||
inconsistent = 0;
|
||||
@@ -1104,13 +1164,25 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
if (!correct_vg) {
|
||||
correct_vg = vg;
|
||||
if (!_update_pv_list(&all_pvs, correct_vg))
|
||||
return_NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp((char *)vg->id.uuid,
|
||||
(char *)correct_vg->id.uuid, ID_LEN)) {
|
||||
inconsistent = 1;
|
||||
inconsistent_vgid = 1;
|
||||
}
|
||||
|
||||
/* FIXME Also ensure contents same - checksums same? */
|
||||
if (correct_vg->seqno != vg->seqno) {
|
||||
inconsistent = 1;
|
||||
if (vg->seqno > correct_vg->seqno)
|
||||
if (vg->seqno > correct_vg->seqno) {
|
||||
if (!_update_pv_list(&all_pvs, vg))
|
||||
return_NULL;
|
||||
correct_vg = vg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1143,17 +1215,42 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
return correct_vg;
|
||||
}
|
||||
|
||||
log_print("Inconsistent metadata copies found - updating "
|
||||
"to use version %u", correct_vg->seqno);
|
||||
/* Don't touch if vgids didn't match */
|
||||
if (inconsistent_vgid) {
|
||||
log_error("Inconsistent metadata UUIDs found for "
|
||||
"volume group %s", vgname);
|
||||
*consistent = 0;
|
||||
return correct_vg;
|
||||
}
|
||||
|
||||
log_print("Inconsistent metadata found for VG %s - updating "
|
||||
"to use version %u", vgname, correct_vg->seqno);
|
||||
|
||||
if (!vg_write(correct_vg)) {
|
||||
log_error("Automatic metadata correction failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!vg_commit(correct_vg)) {
|
||||
log_error("Automatic metadata correction commit "
|
||||
"failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate_items(pvl, &all_pvs) {
|
||||
list_iterate_items(pvl2, &correct_vg->pvs) {
|
||||
if (pvl->pv->dev == pvl2->pv->dev)
|
||||
goto next_pv;
|
||||
}
|
||||
if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid)))
|
||||
return_NULL;
|
||||
log_error("Removing PV %s (%s) that no longer belongs to VG %s",
|
||||
dev_name(pvl->pv->dev), uuid, correct_vg->name);
|
||||
if (!pv_write_orphan(cmd, pvl->pv))
|
||||
return_NULL;
|
||||
next_pv:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
|
||||
@@ -1303,7 +1400,7 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(label_read(dev, &label))) {
|
||||
if (!(label_read(dev, &label, UINT64_C(0)))) {
|
||||
if (warnings)
|
||||
log_error("No physical volume label read from %s",
|
||||
pv_name);
|
||||
@@ -1433,3 +1530,66 @@ int pv_write(struct cmd_context *cmd __attribute((unused)), struct physical_volu
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
{
|
||||
const char *old_vg_name = pv->vg_name;
|
||||
|
||||
pv->vg_name = ORPHAN;
|
||||
pv->status = ALLOCATABLE_PV;
|
||||
|
||||
if (!dev_get_size(pv->dev, &pv->size)) {
|
||||
log_error("%s: Couldn't get size.", dev_name(pv->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pv_write(cmd, pv, NULL, INT64_C(-1))) {
|
||||
log_error("Failed to clear metadata from physical "
|
||||
"volume \"%s\" after removal from \"%s\"",
|
||||
dev_name(pv->dev), old_vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* Returns:
|
||||
* 0 - fail
|
||||
* 1 - success
|
||||
*/
|
||||
int pv_analyze(struct cmd_context *cmd, const char *pv_name,
|
||||
int64_t label_sector)
|
||||
{
|
||||
struct label *label;
|
||||
struct device *dev;
|
||||
struct metadata_area *mda;
|
||||
struct lvmcache_info *info;
|
||||
|
||||
dev = dev_cache_get(pv_name, cmd->filter);
|
||||
if (!dev) {
|
||||
log_error("Device %s not found (or ignored by filtering).",
|
||||
pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* First, scan for LVM labels.
|
||||
*/
|
||||
if (!label_read(dev, &label, label_sector)) {
|
||||
log_error("Could not find LVM label on %s",
|
||||
pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_print("Found label on %s, sector %"PRIu64", type=%s",
|
||||
pv_name, label->sector, label->type);
|
||||
|
||||
/*
|
||||
* Next, loop through metadata areas
|
||||
*/
|
||||
info = label->info;
|
||||
list_iterate_items(mda, &info->mdas)
|
||||
mda->ops->pv_analyze_mda(info->fmt, mda);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -178,6 +178,17 @@ struct metadata_area_ops {
|
||||
struct volume_group * vg, struct metadata_area * mda);
|
||||
int (*vg_remove) (struct format_instance * fi, struct volume_group * vg,
|
||||
struct metadata_area * mda);
|
||||
/*
|
||||
* Check if metadata area belongs to vg
|
||||
*/
|
||||
int (*mda_in_vg) (struct format_instance * fi,
|
||||
struct volume_group * vg, struct metadata_area *mda);
|
||||
/*
|
||||
* Analyze a metadata area on a PV.
|
||||
*/
|
||||
int (*pv_analyze_mda) (const struct format_type * fmt,
|
||||
struct metadata_area *mda);
|
||||
|
||||
};
|
||||
|
||||
struct metadata_area {
|
||||
@@ -423,6 +434,7 @@ struct list *get_vgids(struct cmd_context *cmd, int full_scan);
|
||||
|
||||
int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
struct list *mdas, int64_t label_sector);
|
||||
int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv);
|
||||
|
||||
/* pe_start and pe_end relate to any existing data so that new metadata
|
||||
* areas can avoid overlap */
|
||||
@@ -437,6 +449,8 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
uint64_t pvmetadatasize, struct list *mdas);
|
||||
int pv_resize(struct physical_volume *pv, struct volume_group *vg,
|
||||
uint32_t new_pe_count);
|
||||
int pv_analyze(struct cmd_context *cmd, const char *pv_name,
|
||||
int64_t label_sector);
|
||||
|
||||
struct volume_group *vg_create(struct cmd_context *cmd, const char *name,
|
||||
uint32_t extent_size, uint32_t max_pv,
|
||||
@@ -449,6 +463,8 @@ int vg_extend(struct format_instance *fi, struct volume_group *vg,
|
||||
int pv_count, char **pv_names);
|
||||
int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
||||
uint32_t new_extent_size);
|
||||
int vg_split_mdas(struct cmd_context *cmd, struct volume_group *vg_from,
|
||||
struct volume_group *vg_to);
|
||||
|
||||
/* Manipulate LVs */
|
||||
struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "activate.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "lvm-string.h"
|
||||
#include "str_list.h"
|
||||
#include "locking.h" /* FIXME Should not be used in this file */
|
||||
|
||||
#include "defaults.h" /* FIXME: should this be defaults.h? */
|
||||
@@ -77,6 +78,42 @@ static void _move_lv_segments(struct logical_volume *lv_to, struct logical_volum
|
||||
lv_from->size = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Delete independent/orphan LV, it must acquire lock.
|
||||
*/
|
||||
static int _delete_lv(struct lv_segment *mirrored_seg, struct logical_volume *lv)
|
||||
{
|
||||
struct cmd_context *cmd = mirrored_seg->lv->vg->cmd;
|
||||
struct str_list *sl;
|
||||
|
||||
/* Inherit tags - maybe needed for activation */
|
||||
if (!str_list_match_list(&mirrored_seg->lv->tags, &lv->tags)) {
|
||||
list_iterate_items(sl, &mirrored_seg->lv->tags)
|
||||
if (!str_list_add(cmd->mem, &lv->tags, sl->str)) {
|
||||
log_error("Aborting. Unable to tag.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg_write(mirrored_seg->lv->vg) ||
|
||||
!vg_commit(mirrored_seg->lv->vg)) {
|
||||
log_error("Intermediate VG commit for orphan volume failed.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!activate_lv(cmd, lv))
|
||||
return_0;
|
||||
|
||||
if (!deactivate_lv(cmd, lv))
|
||||
return_0;
|
||||
|
||||
if (!lv_remove(lv))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reduce mirrored_seg to num_mirrors images.
|
||||
*/
|
||||
@@ -205,57 +242,15 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
}
|
||||
|
||||
/* Delete the 'orphan' LVs */
|
||||
for (m = num_mirrors; m < old_area_count; m++) {
|
||||
/* LV is now independent of the mirror so must acquire lock. */
|
||||
if (!activate_lv(mirrored_seg->lv->vg->cmd, seg_lv(mirrored_seg, m))) {
|
||||
stack;
|
||||
for (m = num_mirrors; m < old_area_count; m++)
|
||||
if (!_delete_lv(mirrored_seg, seg_lv(mirrored_seg, m)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, seg_lv(mirrored_seg, m))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (lv1 && !_delete_lv(mirrored_seg, lv1))
|
||||
return 0;
|
||||
|
||||
if (!lv_remove(seg_lv(mirrored_seg, m))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (lv1) {
|
||||
if (!activate_lv(mirrored_seg->lv->vg->cmd, lv1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, lv1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_remove(lv1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (log_lv) {
|
||||
if (!activate_lv(mirrored_seg->lv->vg->cmd, log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_remove(log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (log_lv && !_delete_lv(mirrored_seg, log_lv))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ struct dev_manager;
|
||||
#define SEG_FORMAT1_SUPPORT 0x00000010U
|
||||
#define SEG_VIRTUAL 0x00000020U
|
||||
#define SEG_CANNOT_BE_ZEROED 0x00000040U
|
||||
#define SEG_MONITORED 0x00000080U
|
||||
|
||||
#define seg_is_mirrored(seg) ((seg)->segtype->flags & SEG_AREAS_MIRRORED ? 1 : 0)
|
||||
#define seg_is_striped(seg) ((seg)->segtype->flags & SEG_AREAS_STRIPED ? 1 : 0)
|
||||
@@ -39,6 +40,7 @@ struct dev_manager;
|
||||
#define seg_is_virtual(seg) ((seg)->segtype->flags & SEG_VIRTUAL ? 1 : 0)
|
||||
#define seg_can_split(seg) ((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0)
|
||||
#define seg_cannot_be_zeroed(seg) ((seg)->segtype->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0)
|
||||
#define seg_monitored(seg) ((seg)->segtype->flags & SEG_MONITORED ? 1 : 0)
|
||||
|
||||
#define segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
|
||||
#define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
|
||||
@@ -81,8 +83,9 @@ struct segtype_handler {
|
||||
const struct lv_segment *seg,
|
||||
struct list *modules);
|
||||
void (*destroy) (const struct segment_type * segtype);
|
||||
int (*target_register_events) (struct lv_segment *seg, int events);
|
||||
int (*target_unregister_events) (struct lv_segment *seg, int events);
|
||||
int (*target_monitored) (struct lv_segment *seg, int *pending);
|
||||
int (*target_monitor_events) (struct lv_segment *seg, int events);
|
||||
int (*target_unmonitor_events) (struct lv_segment *seg, int events);
|
||||
};
|
||||
|
||||
struct segment_type *get_segtype_from_string(struct cmd_context *cmd,
|
||||
|
||||
@@ -368,13 +368,12 @@ static int _mirrored_target_present(const struct lv_segment *seg __attribute((un
|
||||
}
|
||||
|
||||
#ifdef DMEVENTD
|
||||
static int _setup_registration(struct dm_pool *mem, struct cmd_context *cmd,
|
||||
char **dso)
|
||||
static int _get_mirror_dso_path(struct cmd_context *cmd, char **dso)
|
||||
{
|
||||
char *path;
|
||||
const char *libpath;
|
||||
|
||||
if (!(path = dm_pool_alloc(mem, PATH_MAX))) {
|
||||
if (!(path = dm_pool_alloc(cmd->mem, PATH_MAX))) {
|
||||
log_error("Failed to allocate dmeventd library path.");
|
||||
return 0;
|
||||
}
|
||||
@@ -389,78 +388,105 @@ static int _setup_registration(struct dm_pool *mem, struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME This gets run while suspended and performs banned operations. */
|
||||
/* FIXME Merge these two functions */
|
||||
static int _target_register_events(struct lv_segment *seg,
|
||||
int events)
|
||||
static struct dm_event_handler *_create_dm_event_handler(const char *dmname,
|
||||
const char *dso,
|
||||
enum dm_event_mask mask)
|
||||
{
|
||||
struct dm_event_handler *dmevh;
|
||||
|
||||
if (!(dmevh = dm_event_handler_create()))
|
||||
return_0;
|
||||
|
||||
if (dm_event_handler_set_dso(dmevh, dso))
|
||||
goto fail;
|
||||
|
||||
if (dm_event_handler_set_dev_name(dmevh, dmname))
|
||||
goto fail;
|
||||
|
||||
dm_event_handler_set_event_mask(dmevh, mask);
|
||||
return dmevh;
|
||||
|
||||
fail:
|
||||
dm_event_handler_destroy(dmevh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _target_monitored(struct lv_segment *seg, int *pending)
|
||||
{
|
||||
char *dso, *name;
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
struct dm_event_handler *handler;
|
||||
enum dm_event_mask evmask = 0;
|
||||
struct dm_event_handler *dmevh;
|
||||
|
||||
lv = seg->lv;
|
||||
vg = lv->vg;
|
||||
|
||||
if (!_setup_registration(vg->cmd->mem, vg->cmd, &dso)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
*pending = 0;
|
||||
if (!_get_mirror_dso_path(vg->cmd, &dso))
|
||||
return_0;
|
||||
|
||||
if (!(name = build_dm_name(vg->cmd->mem, vg->name, lv->name, NULL)))
|
||||
return_0;
|
||||
|
||||
if (!(handler = dm_event_handler_create()))
|
||||
if (!(dmevh = _create_dm_event_handler(name, dso, DM_EVENT_ALL_ERRORS)))
|
||||
return_0;
|
||||
|
||||
dm_event_handler_set_dso(handler, dso);
|
||||
dm_event_handler_set_name(handler, name);
|
||||
dm_event_handler_set_events(handler, DM_EVENT_ALL_ERRORS);
|
||||
if (!dm_event_register(handler)) {
|
||||
dm_event_handler_destroy(handler);
|
||||
return_0;
|
||||
if (dm_event_get_registered_device(dmevh, 0)) {
|
||||
dm_event_handler_destroy(dmevh);
|
||||
return 0;
|
||||
}
|
||||
dm_event_handler_destroy(handler);
|
||||
|
||||
log_info("Registered %s for events", name);
|
||||
evmask = dm_event_handler_get_event_mask(dmevh);
|
||||
if (evmask & DM_EVENT_REGISTRATION_PENDING) {
|
||||
*pending = 1;
|
||||
evmask &= ~DM_EVENT_REGISTRATION_PENDING;
|
||||
}
|
||||
|
||||
dm_event_handler_destroy(dmevh);
|
||||
|
||||
return evmask;
|
||||
}
|
||||
|
||||
/* FIXME This gets run while suspended and performs banned operations. */
|
||||
static int _target_set_events(struct lv_segment *seg, int evmask, int set)
|
||||
{
|
||||
char *dso, *name;
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
struct dm_event_handler *dmevh;
|
||||
int r;
|
||||
|
||||
lv = seg->lv;
|
||||
vg = lv->vg;
|
||||
|
||||
if (!_get_mirror_dso_path(vg->cmd, &dso))
|
||||
return_0;
|
||||
|
||||
if (!(name = build_dm_name(vg->cmd->mem, vg->name, lv->name, NULL)))
|
||||
return_0;
|
||||
|
||||
if (!(dmevh = _create_dm_event_handler(name, dso, DM_EVENT_ALL_ERRORS)))
|
||||
return_0;
|
||||
|
||||
r = set ? dm_event_register_handler(dmevh) : dm_event_unregister_handler(dmevh);
|
||||
dm_event_handler_destroy(dmevh);
|
||||
if (!r)
|
||||
return_0;
|
||||
|
||||
log_info("%s %s for events", set ? "Monitored" : "Unmonitored", name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _target_unregister_events(struct lv_segment *seg,
|
||||
int events)
|
||||
static int _target_monitor_events(struct lv_segment *seg, int events)
|
||||
{
|
||||
char *dso;
|
||||
char *name;
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
struct dm_event_handler *handler;
|
||||
return _target_set_events(seg, events, 1);
|
||||
}
|
||||
|
||||
lv = seg->lv;
|
||||
vg = lv->vg;
|
||||
|
||||
/* FIXME Remove this and use handle to avoid config file race */
|
||||
if (!_setup_registration(vg->cmd->mem, vg->cmd, &dso))
|
||||
return_0;
|
||||
|
||||
if (!(name = build_dm_name(vg->cmd->mem, vg->name, lv->name, NULL)))
|
||||
return_0;
|
||||
|
||||
if (!(handler = dm_event_handler_create()))
|
||||
return_0;
|
||||
|
||||
dm_event_handler_set_dso(handler, dso);
|
||||
dm_event_handler_set_name(handler, name);
|
||||
dm_event_handler_set_events(handler, DM_EVENT_ALL_ERRORS);
|
||||
if (!dm_event_unregister(handler)) {
|
||||
dm_event_handler_destroy(handler);
|
||||
return_0;
|
||||
}
|
||||
dm_event_handler_destroy(handler);
|
||||
|
||||
log_info("Unregistered %s for events", name);
|
||||
|
||||
return 1;
|
||||
static int _target_unmonitor_events(struct lv_segment *seg, int events)
|
||||
{
|
||||
return _target_set_events(seg, events, 0);
|
||||
}
|
||||
|
||||
#endif /* DMEVENTD */
|
||||
@@ -504,8 +530,9 @@ static struct segtype_handler _mirrored_ops = {
|
||||
.target_percent = _mirrored_target_percent,
|
||||
.target_present = _mirrored_target_present,
|
||||
#ifdef DMEVENTD
|
||||
.target_register_events = _target_register_events,
|
||||
.target_unregister_events = _target_unregister_events,
|
||||
.target_monitored = _target_monitored,
|
||||
.target_monitor_events = _target_monitor_events,
|
||||
.target_unmonitor_events = _target_unmonitor_events,
|
||||
#endif
|
||||
#endif
|
||||
.modules_needed = _mirrored_modules_needed,
|
||||
@@ -530,7 +557,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
|
||||
segtype->ops = &_mirrored_ops;
|
||||
segtype->name = "mirror";
|
||||
segtype->private = NULL;
|
||||
segtype->flags = SEG_AREAS_MIRRORED;
|
||||
segtype->flags = SEG_AREAS_MIRRORED | SEG_MONITORED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#ifndef _LVM_LIB_H
|
||||
#define _LVM_LIB_H
|
||||
|
||||
#include <configure.h>
|
||||
#include "configure.h"
|
||||
|
||||
#define _REENTRANT
|
||||
#define _GNU_SOURCE
|
||||
|
||||
@@ -66,7 +66,8 @@ int create_temp_name(const char *dir, char *buffer, size_t len, int *fd)
|
||||
if (!fcntl(*fd, F_SETLK, &lock))
|
||||
return 1;
|
||||
|
||||
close(*fd);
|
||||
if (close(*fd))
|
||||
log_sys_error("close", buffer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -239,7 +240,8 @@ void sync_dir(const char *file)
|
||||
if (fsync(fd) && (errno != EROFS) && (errno != EINVAL))
|
||||
log_sys_error("fsync", dir);
|
||||
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("close", dir);
|
||||
|
||||
out:
|
||||
dm_free(dir);
|
||||
@@ -254,6 +256,8 @@ void sync_dir(const char *file)
|
||||
int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only)
|
||||
{
|
||||
int lockfd;
|
||||
char *dir;
|
||||
char *c;
|
||||
struct flock lock = {
|
||||
.l_type = lock_type,
|
||||
.l_whence = 0,
|
||||
@@ -261,6 +265,21 @@ int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only)
|
||||
.l_len = 0
|
||||
};
|
||||
|
||||
if (!(dir = dm_strdup(file))) {
|
||||
log_error("fcntl_lock_file failed in strdup.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((c = strrchr(dir, '/')))
|
||||
*c = '\0';
|
||||
|
||||
if (!create_dir(dir)) {
|
||||
dm_free(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dm_free(dir);
|
||||
|
||||
log_very_verbose("Locking %s (%s, %hd)", file,
|
||||
(lock_type == F_WRLCK) ? "F_WRLCK" : "F_RDLCK",
|
||||
lock_type);
|
||||
|
||||
@@ -36,18 +36,38 @@ int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...)
|
||||
}
|
||||
|
||||
/*
|
||||
* Device layer names are all of the form <vg>-<lv>-<layer>, any
|
||||
* other hyphens that appear in these names are quoted with yet
|
||||
* another hyphen. The top layer of any device has no layer
|
||||
* name. eg, vg0-lvol0.
|
||||
* Count occurences of 'c' in 'str' until we reach a null char.
|
||||
*
|
||||
* Returns:
|
||||
* len - incremented for each char we encounter, whether 'c' or not.
|
||||
* count - number of occurences of 'c'
|
||||
*/
|
||||
static void _count_hyphens(const char *str, size_t *len, int *hyphens)
|
||||
void count_chars(const char *str, size_t *len, int *count,
|
||||
const char c)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
for (ptr = str; *ptr; ptr++, (*len)++)
|
||||
if (*ptr == '-')
|
||||
(*hyphens)++;
|
||||
if (*ptr == c)
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count occurences of 'c' in 'str' of length 'size'.
|
||||
*
|
||||
* Returns:
|
||||
* # of occurences of 'c'
|
||||
*/
|
||||
unsigned count_chars_len(const char *str, size_t size, const char c)
|
||||
{
|
||||
int i;
|
||||
unsigned count=0;
|
||||
|
||||
for (i=0; i < size; i++)
|
||||
if (str[i] == c)
|
||||
count++;
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -73,11 +93,11 @@ char *build_dm_name(struct dm_pool *mem, const char *vgname,
|
||||
int hyphens = 1;
|
||||
char *r, *out;
|
||||
|
||||
_count_hyphens(vgname, &len, &hyphens);
|
||||
_count_hyphens(lvname, &len, &hyphens);
|
||||
count_chars(vgname, &len, &hyphens, '-');
|
||||
count_chars(lvname, &len, &hyphens, '-');
|
||||
|
||||
if (layer && *layer) {
|
||||
_count_hyphens(layer, &len, &hyphens);
|
||||
count_chars(layer, &len, &hyphens, '-');
|
||||
hyphens++;
|
||||
}
|
||||
|
||||
@@ -105,6 +125,12 @@ char *build_dm_name(struct dm_pool *mem, const char *vgname,
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device layer names are all of the form <vg>-<lv>-<layer>, any
|
||||
* other hyphens that appear in these names are quoted with yet
|
||||
* another hyphen. The top layer of any device has no layer
|
||||
* name. eg, vg0-lvol0.
|
||||
*/
|
||||
int validate_name(const char *n)
|
||||
{
|
||||
register char c;
|
||||
|
||||
@@ -30,4 +30,8 @@ char *build_dm_name(struct dm_pool *mem, const char *vg,
|
||||
|
||||
int validate_name(const char *n);
|
||||
|
||||
void count_chars(const char *str, size_t *len, int *count,
|
||||
char c);
|
||||
unsigned count_chars_len(const char *str, size_t size, char c);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 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 General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU 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
|
||||
*/
|
||||
|
||||
#ifndef _LVM_MATCHER_H
|
||||
#define _LVM_MATCHER_H
|
||||
|
||||
struct matcher;
|
||||
struct matcher *matcher_create(struct dm_pool *mem, const char **patterns,
|
||||
unsigned num);
|
||||
|
||||
int matcher_run(struct matcher *m, const char *begin);
|
||||
|
||||
#endif
|
||||
@@ -18,67 +18,67 @@
|
||||
* Display Fn, Unique format identifier */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid")
|
||||
FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name")
|
||||
FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr")
|
||||
FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major")
|
||||
FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor")
|
||||
FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, "lv_kernel_major")
|
||||
FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_minor")
|
||||
FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size")
|
||||
FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count")
|
||||
FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin")
|
||||
FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent")
|
||||
FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent")
|
||||
FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv")
|
||||
FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags")
|
||||
FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log")
|
||||
FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules")
|
||||
FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid", "Unique identifier")
|
||||
FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name", "Name. LVs created for internal use are enclosed in brackets.")
|
||||
FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr", "Various attributes - see man page.")
|
||||
FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major", "Persistent major number or -1 if not persistent.")
|
||||
FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor", "Persistent minor number or -1 if not persistent.")
|
||||
FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, "lv_kernel_major", "Currently assigned major number or -1 if LV is not active.")
|
||||
FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_minor", "Currently assigned minor number or -1 if LV is not active.")
|
||||
FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size", "Size of LV in current units.")
|
||||
FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count", "Number of segments in LV.")
|
||||
FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin", "For snapshots, the origin device of this LV")
|
||||
FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent", "For snapshots, the percentage full if LV is active.")
|
||||
FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent", "For mirrors and pvmove, current percentage in-sync.")
|
||||
FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv", "For pvmove, Source PV of temporary LV created by pvmove")
|
||||
FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags", "Tags, if any.")
|
||||
FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log", "For mirrors, the LV holding the synchronisation log.")
|
||||
FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules", "Kernel device-mapper modules required for this LV.")
|
||||
|
||||
FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
|
||||
FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
|
||||
FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, "pv_size")
|
||||
FIELD(PVS, pv, NUM, "DevSize", dev, 7, devsize, "dev_size")
|
||||
FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, "pe_start")
|
||||
FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, "pv_free")
|
||||
FIELD(PVS, pv, NUM, "Used", id, 4, pvused, "pv_used")
|
||||
FIELD(PVS, pv, STR, "PV", dev, 10, dev_name, "pv_name")
|
||||
FIELD(PVS, pv, STR, "Attr", status, 4, pvstatus, "pv_attr")
|
||||
FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, "pv_pe_count")
|
||||
FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, "pv_pe_alloc_count")
|
||||
FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, "pv_tags")
|
||||
FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt", "Type of metadata.")
|
||||
FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid", "Unique identifier.")
|
||||
FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, "pv_size", "Size of PV in current units.")
|
||||
FIELD(PVS, pv, NUM, "DevSize", dev, 7, devsize, "dev_size", "Size of underlying device in current units.")
|
||||
FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, "pe_start", "Offset to the start of data on the underlying device.")
|
||||
FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, "pv_free", "Total amount of unallocated space in current units.")
|
||||
FIELD(PVS, pv, NUM, "Used", id, 4, pvused, "pv_used", "Total amount of allocated space in current units.")
|
||||
FIELD(PVS, pv, STR, "PV", dev, 10, dev_name, "pv_name", "Name.")
|
||||
FIELD(PVS, pv, STR, "Attr", status, 4, pvstatus, "pv_attr", "Various attributes - see man page.")
|
||||
FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, "pv_pe_count", "Total number of Physical Extents.")
|
||||
FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, "pv_pe_alloc_count", "Total number of allocated Physical Extents.")
|
||||
FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, "pv_tags", "Tags, if any.")
|
||||
|
||||
FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, "vg_fmt")
|
||||
FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, "vg_uuid")
|
||||
FIELD(VGS, vg, STR, "VG", name, 4, string, "vg_name")
|
||||
FIELD(VGS, vg, STR, "Attr", cmd, 5, vgstatus, "vg_attr")
|
||||
FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, "vg_size")
|
||||
FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, "vg_free")
|
||||
FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, "vg_sysid")
|
||||
FIELD(VGS, vg, NUM, "Ext", extent_size, 3, size32, "vg_extent_size")
|
||||
FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, "vg_extent_count")
|
||||
FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, "vg_free_count")
|
||||
FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, "max_lv")
|
||||
FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, "max_pv")
|
||||
FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, "pv_count")
|
||||
FIELD(VGS, vg, NUM, "#LV", lv_count, 3, uint32, "lv_count")
|
||||
FIELD(VGS, vg, NUM, "#SN", snapshot_count, 3, uint32, "snap_count")
|
||||
FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, "vg_seqno")
|
||||
FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags")
|
||||
FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, "vg_fmt", "Type of metadata.")
|
||||
FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, "vg_uuid", "Unique identifier.")
|
||||
FIELD(VGS, vg, STR, "VG", name, 4, string, "vg_name", "Name.")
|
||||
FIELD(VGS, vg, STR, "Attr", cmd, 5, vgstatus, "vg_attr", "Various attributes - see man page.")
|
||||
FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, "vg_size", "Total size of VG in current units.")
|
||||
FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, "vg_free", "Total amount of free space in current units.")
|
||||
FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, "vg_sysid", "System ID indicating when and where it was created.")
|
||||
FIELD(VGS, vg, NUM, "Ext", extent_size, 3, size32, "vg_extent_size", "Size of Physical Extents in current units.")
|
||||
FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, "vg_extent_count", "Total number of Physical Extents.")
|
||||
FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, "vg_free_count", "Total number of unallocated Physical Extents.")
|
||||
FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, "max_lv", "Maximum number of LVs allowed in VG or 0 if unlimited.")
|
||||
FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, "max_pv", "Maximum number of PVs allowed in VG or 0 if unlimited.")
|
||||
FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, "pv_count", "Number of PVs.")
|
||||
FIELD(VGS, vg, NUM, "#LV", lv_count, 3, uint32, "lv_count", "Number of LVs.")
|
||||
FIELD(VGS, vg, NUM, "#SN", snapshot_count, 3, uint32, "snap_count", "Number of snapshots.")
|
||||
FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, "vg_seqno", "Revision number of internal metadata. Incremented whenever it changes.")
|
||||
FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags", "Tags, if any.")
|
||||
|
||||
FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype")
|
||||
FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size")
|
||||
FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start")
|
||||
FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size")
|
||||
FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags")
|
||||
FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices")
|
||||
FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype", "Type of LV segment")
|
||||
FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes", "Number of stripes or mirror legs.")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize", "For stripes, amount of data placed on one device before switching to the next.")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size", "For stripes, amount of data placed on one device before switching to the next.")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize", "For mirrors, the unit of data copied when synchronising devices.")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size", "For mirrors, the unit of data copied when synchronising devices.")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize", "For snapshots, the unit of data used when tracking changes.")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size", "For snapshots, the unit of data used when tracking changes.")
|
||||
FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start", "Offset within the LV to the start of the segment in current units.")
|
||||
FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size", "Size of segment in current units.")
|
||||
FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags", "Tags, if any.")
|
||||
FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices", "Underlying devices used with starting extent numbers.")
|
||||
|
||||
FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start")
|
||||
FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size")
|
||||
FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start", "Physical Extent number of start of segment.")
|
||||
FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size", "Number of extents in segment.")
|
||||
/* *INDENT-ON* */
|
||||
|
||||
1187
lib/report/report.c
1187
lib/report/report.c
File diff suppressed because it is too large
Load Diff
@@ -115,4 +115,17 @@ dm_split_lvm_name
|
||||
dm_split_words
|
||||
dm_snprintf
|
||||
dm_basename
|
||||
dm_saprintf
|
||||
dm_asprintf
|
||||
dm_report_init
|
||||
dm_report_object
|
||||
dm_report_output
|
||||
dm_report_free
|
||||
dm_report_get_private
|
||||
dm_report_field_string
|
||||
dm_report_field_int
|
||||
dm_report_field_int32
|
||||
dm_report_field_uint32
|
||||
dm_report_field_uint64
|
||||
dm_report_field_set_value
|
||||
dm_regex_create
|
||||
dm_regex_match
|
||||
|
||||
@@ -24,8 +24,12 @@ SOURCES =\
|
||||
libdm-file.c \
|
||||
libdm-deptree.c \
|
||||
libdm-string.c \
|
||||
libdm-report.c \
|
||||
mm/dbg_malloc.c \
|
||||
mm/pool.c \
|
||||
regex/matcher.c \
|
||||
regex/parse_rx.c \
|
||||
regex/ttree.c \
|
||||
$(interface)/libdm-iface.c
|
||||
|
||||
INCLUDES = -I$(interface)
|
||||
@@ -89,7 +93,7 @@ install_ioctl_static: ioctl/libdevmapper.a
|
||||
.PHONY: distclean_lib distclean
|
||||
|
||||
distclean_lib:
|
||||
$(RM) libdm-common.h libdevmapper.pc
|
||||
$(RM) libdevmapper.pc
|
||||
|
||||
distclean: distclean_lib
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_BITSET_H
|
||||
#define _LVM_BITSET_H
|
||||
#ifndef _DM_BITSET_H
|
||||
#define _DM_BITSET_H
|
||||
|
||||
#include "pool.h"
|
||||
|
||||
|
||||
@@ -68,14 +68,14 @@ static struct dm_hash_node *_create_node(const char *str, unsigned len)
|
||||
return n;
|
||||
}
|
||||
|
||||
static unsigned long _hash(const unsigned char *str, unsigned len)
|
||||
static unsigned long _hash(const char *str, unsigned len)
|
||||
{
|
||||
unsigned long h = 0, g;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
h <<= 4;
|
||||
h += _nums[*str++];
|
||||
h += _nums[(unsigned char) *str++];
|
||||
g = h & ((unsigned long) 0xf << 16u);
|
||||
if (g) {
|
||||
h ^= g >> 16u;
|
||||
@@ -230,12 +230,14 @@ void dm_hash_wipe(struct dm_hash_table *t)
|
||||
t->num_nodes = 0u;
|
||||
}
|
||||
|
||||
char *dm_hash_get_key(struct dm_hash_table *t, struct dm_hash_node *n)
|
||||
char *dm_hash_get_key(struct dm_hash_table *t __attribute((unused)),
|
||||
struct dm_hash_node *n)
|
||||
{
|
||||
return n->key;
|
||||
}
|
||||
|
||||
void *dm_hash_get_data(struct dm_hash_table *t, struct dm_hash_node *n)
|
||||
void *dm_hash_get_data(struct dm_hash_table *t __attribute((unused)),
|
||||
struct dm_hash_node *n)
|
||||
{
|
||||
return n->data;
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_HASH_H
|
||||
#define _LVM_HASH_H
|
||||
#ifndef _DM_HASH_H
|
||||
#define _DM_HASH_H
|
||||
|
||||
struct hash_table;
|
||||
struct hash_node;
|
||||
|
||||
@@ -149,7 +149,8 @@ static int _get_proc_number(const char *file, const char *name,
|
||||
if (!strcmp(name, nm)) {
|
||||
if (number) {
|
||||
*number = num;
|
||||
fclose(fl);
|
||||
if (fclose(fl))
|
||||
log_error("%s: fclose failed: %s", file, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
dm_bit_set(_dm_bitset, num);
|
||||
@@ -158,7 +159,8 @@ static int _get_proc_number(const char *file, const char *name,
|
||||
c = fgetc(fl);
|
||||
} while (c != EOF && c != '\n');
|
||||
}
|
||||
fclose(fl);
|
||||
if (fclose(fl))
|
||||
log_error("%s: fclose failed: %s", file, strerror(errno));
|
||||
|
||||
if (number) {
|
||||
log_error("%s: No entry for %s found", file, name);
|
||||
@@ -431,12 +433,12 @@ static int _dm_task_get_info_v1(struct dm_task *dmt, struct dm_info *info)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *_dm_task_get_name_v1(struct dm_task *dmt)
|
||||
static const char *_dm_task_get_name_v1(const struct dm_task *dmt)
|
||||
{
|
||||
return (dmt->dmi.v1->name);
|
||||
}
|
||||
|
||||
static const char *_dm_task_get_uuid_v1(struct dm_task *dmt)
|
||||
static const char *_dm_task_get_uuid_v1(const struct dm_task *dmt)
|
||||
{
|
||||
return (dmt->dmi.v1->uuid);
|
||||
}
|
||||
@@ -922,7 +924,7 @@ int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *dm_task_get_name(struct dm_task *dmt)
|
||||
const char *dm_task_get_name(const struct dm_task *dmt)
|
||||
{
|
||||
#ifdef DM_COMPAT
|
||||
if (_dm_version == 1)
|
||||
@@ -932,7 +934,7 @@ const char *dm_task_get_name(struct dm_task *dmt)
|
||||
return (dmt->dmi.v4->name);
|
||||
}
|
||||
|
||||
const char *dm_task_get_uuid(struct dm_task *dmt)
|
||||
const char *dm_task_get_uuid(const struct dm_task *dmt)
|
||||
{
|
||||
#ifdef DM_COMPAT
|
||||
if (_dm_version == 1)
|
||||
@@ -1322,7 +1324,7 @@ static int _process_mapper_dir(struct dm_task *dmt)
|
||||
|
||||
dir = dm_dir();
|
||||
if (!(d = opendir(dir))) {
|
||||
fprintf(stderr, "opendir %s: %s", dir, strerror(errno));
|
||||
log_error("opendir %s: %s", dir, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1335,9 +1337,8 @@ static int _process_mapper_dir(struct dm_task *dmt)
|
||||
dm_task_run(dmt);
|
||||
}
|
||||
|
||||
if (closedir(d)) {
|
||||
fprintf(stderr, "closedir %s: %s", dir, strerror(errno));
|
||||
}
|
||||
if (closedir(d))
|
||||
log_error("closedir %s: %s", dir, strerror(errno));
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1554,7 +1555,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
dmi->flags |= DM_SKIP_BDGET_FLAG;
|
||||
|
||||
log_debug("dm %s %s %s%s%s %s%.0d%s%.0d%s"
|
||||
"%s%c%c%s %.0llu %s [%u]",
|
||||
"%s%c%c%s %.0" PRIu64 " %s [%u]",
|
||||
_cmd_data_v4[dmt->type].name,
|
||||
dmi->name, dmi->uuid, dmt->newname ? " " : "",
|
||||
dmt->newname ? dmt->newname : "",
|
||||
|
||||
@@ -124,17 +124,17 @@ struct dm_names {
|
||||
};
|
||||
|
||||
struct dm_versions {
|
||||
uint32_t next; /* Offset to next struct from start of this struct */
|
||||
uint32_t version[3];
|
||||
uint32_t next; /* Offset to next struct from start of this struct */
|
||||
uint32_t version[3];
|
||||
|
||||
char name[0];
|
||||
char name[0];
|
||||
};
|
||||
|
||||
int dm_get_library_version(char *version, size_t size);
|
||||
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size);
|
||||
int dm_task_get_info(struct dm_task *dmt, struct dm_info *dmi);
|
||||
const char *dm_task_get_name(struct dm_task *dmt);
|
||||
const char *dm_task_get_uuid(struct dm_task *dmt);
|
||||
const char *dm_task_get_name(const struct dm_task *dmt);
|
||||
const char *dm_task_get_uuid(const struct dm_task *dmt);
|
||||
|
||||
struct dm_deps *dm_task_get_deps(struct dm_task *dmt);
|
||||
struct dm_names *dm_task_get_names(struct dm_task *dmt);
|
||||
@@ -236,12 +236,12 @@ int dm_tree_add_dev(struct dm_tree *tree, uint32_t major, uint32_t minor);
|
||||
* Add a new node to the tree if it doesn't already exist.
|
||||
*/
|
||||
struct dm_tree_node *dm_tree_add_new_dev(struct dm_tree *tree,
|
||||
const char *name,
|
||||
const char *uuid,
|
||||
uint32_t major, uint32_t minor,
|
||||
int read_only,
|
||||
int clear_inactive,
|
||||
void *context);
|
||||
const char *name,
|
||||
const char *uuid,
|
||||
uint32_t major, uint32_t minor,
|
||||
int read_only,
|
||||
int clear_inactive,
|
||||
void *context);
|
||||
|
||||
/*
|
||||
* Search for a node in the tree.
|
||||
@@ -289,16 +289,16 @@ int dm_tree_deactivate_children(struct dm_tree_node *dnode,
|
||||
* Ignores devices that don't have a uuid starting with uuid_prefix.
|
||||
*/
|
||||
int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len);
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len);
|
||||
|
||||
/*
|
||||
* Resume a device plus all dependencies.
|
||||
* Ignores devices that don't have a uuid starting with uuid_prefix.
|
||||
*/
|
||||
int dm_tree_activate_children(struct dm_tree_node *dnode,
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len);
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len);
|
||||
|
||||
/*
|
||||
* Suspend a device plus all dependencies.
|
||||
@@ -626,7 +626,108 @@ char *dm_basename(const char *path);
|
||||
/*
|
||||
* Returns size of a buffer which is allocated with dm_malloc.
|
||||
* Pointer to the buffer is stored in *buf.
|
||||
* Returns -1 on failure leaving buf undefined.
|
||||
*/
|
||||
int dm_saprintf(char **buf, const char *format, ...);
|
||||
int dm_asprintf(char **buf, const char *format, ...);
|
||||
|
||||
/*********************
|
||||
* regular expressions
|
||||
*********************/
|
||||
struct dm_regex;
|
||||
|
||||
/*
|
||||
* Initialise an array of num patterns for matching.
|
||||
* Uses memory from mem.
|
||||
*/
|
||||
struct dm_regex *dm_regex_create(struct dm_pool *mem, const char **patterns,
|
||||
unsigned num_patterns);
|
||||
|
||||
/*
|
||||
* Match string s against the patterns.
|
||||
* Returns the index of the highest pattern in the array that matches,
|
||||
* or -1 if none match.
|
||||
*/
|
||||
int dm_regex_match(struct dm_regex *regex, const char *s);
|
||||
|
||||
/*********************
|
||||
* reporting functions
|
||||
*********************/
|
||||
|
||||
struct dm_report_object_type {
|
||||
uint32_t id; /* Powers of 2 */
|
||||
const char *desc;
|
||||
const char *prefix; /* field id string prefix (optional) */
|
||||
void *(*data_fn)(void *object); /* callback from report_object() */
|
||||
};
|
||||
|
||||
struct dm_report_field;
|
||||
|
||||
/*
|
||||
* dm_report_field_type flags
|
||||
*/
|
||||
#define DM_REPORT_FIELD_MASK 0x000000FF
|
||||
#define DM_REPORT_FIELD_ALIGN_MASK 0x0000000F
|
||||
#define DM_REPORT_FIELD_ALIGN_LEFT 0x00000001
|
||||
#define DM_REPORT_FIELD_ALIGN_RIGHT 0x00000002
|
||||
#define DM_REPORT_FIELD_TYPE_MASK 0x000000F0
|
||||
#define DM_REPORT_FIELD_TYPE_STRING 0x00000010
|
||||
#define DM_REPORT_FIELD_TYPE_NUMBER 0x00000020
|
||||
|
||||
struct dm_report;
|
||||
struct dm_report_field_type {
|
||||
uint32_t type; /* object type id */
|
||||
uint32_t flags; /* DM_REPORT_FIELD_* */
|
||||
uint32_t offset; /* byte offset in the object */
|
||||
int32_t width; /* default width */
|
||||
const char id[32]; /* string used to specify the field */
|
||||
const char heading[32]; /* string printed in header */
|
||||
int (*report_fn)(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field, const void *data,
|
||||
void *private);
|
||||
const char *desc; /* description of the field */
|
||||
};
|
||||
|
||||
/*
|
||||
* dm_report_init output_flags
|
||||
*/
|
||||
#define DM_REPORT_OUTPUT_MASK 0x000000FF
|
||||
#define DM_REPORT_OUTPUT_ALIGNED 0x00000001
|
||||
#define DM_REPORT_OUTPUT_BUFFERED 0x00000002
|
||||
#define DM_REPORT_OUTPUT_HEADINGS 0x00000004
|
||||
|
||||
struct dm_report *dm_report_init(uint32_t *report_types,
|
||||
const struct dm_report_object_type *types,
|
||||
const struct dm_report_field_type *fields,
|
||||
const char *output_fields,
|
||||
const char *output_separator,
|
||||
uint32_t output_flags,
|
||||
const char *sort_keys,
|
||||
void *private);
|
||||
int dm_report_object(struct dm_report *rh, void *object);
|
||||
int dm_report_output(struct dm_report *rh);
|
||||
void dm_report_free(struct dm_report *rh);
|
||||
|
||||
/*
|
||||
* Report functions are provided for simple data types.
|
||||
* They take care of allocating copies of the data.
|
||||
*/
|
||||
int dm_report_field_string(struct dm_report *rh, struct dm_report_field *field,
|
||||
const char **data);
|
||||
int dm_report_field_int32(struct dm_report *rh, struct dm_report_field *field,
|
||||
const int32_t *data);
|
||||
int dm_report_field_uint32(struct dm_report *rh, struct dm_report_field *field,
|
||||
const uint32_t *data);
|
||||
int dm_report_field_int(struct dm_report *rh, struct dm_report_field *field,
|
||||
const int *data);
|
||||
int dm_report_field_uint64(struct dm_report *rh, struct dm_report_field *field,
|
||||
const uint64_t *data);
|
||||
|
||||
/*
|
||||
* For custom fields, allocate the data in 'mem' and use
|
||||
* dm_report_field_set_value().
|
||||
* 'sortvalue' may be NULL if it matches 'value'
|
||||
*/
|
||||
void dm_report_field_set_value(struct dm_report_field *field, const void *value,
|
||||
const void *sortvalue);
|
||||
|
||||
#endif /* LIB_DEVICE_MAPPER_H */
|
||||
|
||||
@@ -38,8 +38,8 @@ static int _verbose = 0;
|
||||
* Library users can provide their own logging
|
||||
* function.
|
||||
*/
|
||||
static void _default_log(int level, const char *file, int line,
|
||||
const char *f, ...)
|
||||
static void _default_log(int level, const char *file __attribute((unused)),
|
||||
int line __attribute((unused)), const char *f, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
|
||||
@@ -28,6 +28,4 @@ int rm_dev_node(const char *dev_name);
|
||||
int rename_dev_node(const char *old_name, const char *new_name);
|
||||
void update_devs(void);
|
||||
|
||||
#define DM_LIB_VERSION @DM_LIB_VERSION@
|
||||
|
||||
#endif
|
||||
@@ -1212,7 +1212,9 @@ static int _build_dev_string(char *devbuf, size_t bufsize, struct dm_tree_node *
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _emit_areas_line(struct dm_task *dmt, struct load_segment *seg, char *params, size_t paramsize, int *pos)
|
||||
static int _emit_areas_line(struct dm_task *dmt __attribute((unused)),
|
||||
struct load_segment *seg, char *params,
|
||||
size_t paramsize, int *pos)
|
||||
{
|
||||
struct seg_area *area;
|
||||
char devbuf[10];
|
||||
|
||||
863
libdm/libdm-report.c
Normal file
863
libdm/libdm-report.c
Normal file
@@ -0,0 +1,863 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of device-mapper userspace tools.
|
||||
* The code is based on LVM2 report function.
|
||||
*
|
||||
* 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 General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU 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 "libdevmapper.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
|
||||
/*
|
||||
* Internal flags
|
||||
*/
|
||||
#define RH_SORT_REQUIRED 0x00000100
|
||||
#define RH_HEADINGS_PRINTED 0x00000200
|
||||
|
||||
struct dm_report {
|
||||
struct dm_pool *mem;
|
||||
|
||||
uint32_t report_types;
|
||||
const char *field_prefix;
|
||||
uint32_t flags;
|
||||
const char *separator;
|
||||
|
||||
uint32_t keys_count;
|
||||
|
||||
/* Ordered list of fields needed for this report */
|
||||
struct list field_props;
|
||||
|
||||
/* Rows of report data */
|
||||
struct list rows;
|
||||
|
||||
/* Array of field definitions */
|
||||
const struct dm_report_field_type *fields;
|
||||
const struct dm_report_object_type *types;
|
||||
|
||||
/* To store caller private data */
|
||||
void *private;
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal per-field flags
|
||||
*/
|
||||
#define FLD_HIDDEN 0x00000100
|
||||
#define FLD_SORT_KEY 0x00000200
|
||||
#define FLD_ASCENDING 0x00000400
|
||||
#define FLD_DESCENDING 0x00000800
|
||||
|
||||
struct field_properties {
|
||||
struct list list;
|
||||
uint32_t field_num;
|
||||
uint32_t sort_posn;
|
||||
int32_t width;
|
||||
const struct dm_report_object_type *type;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* Report data field
|
||||
*/
|
||||
struct dm_report_field {
|
||||
struct list list;
|
||||
struct field_properties *props;
|
||||
|
||||
const char *report_string; /* Formatted ready for display */
|
||||
const void *sort_value; /* Raw value for sorting */
|
||||
};
|
||||
|
||||
struct row {
|
||||
struct list list;
|
||||
struct dm_report *rh;
|
||||
struct list fields; /* Fields in display order */
|
||||
struct dm_report_field *(*sort_fields)[]; /* Fields in sort order */
|
||||
};
|
||||
|
||||
static const struct dm_report_object_type *_find_type(struct dm_report *rh,
|
||||
uint32_t report_type)
|
||||
{
|
||||
const struct dm_report_object_type *t;
|
||||
|
||||
for (t = rh->types; t->data_fn; t++)
|
||||
if (t->id == report_type)
|
||||
return t;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Data-munging functions to prepare each data type for display and sorting
|
||||
*/
|
||||
|
||||
int dm_report_field_string(struct dm_report *rh,
|
||||
struct dm_report_field *field, const char **data)
|
||||
{
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_strdup(rh->mem, *data))) {
|
||||
log_error("dm_report_field_string: dm_pool_strdup failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
field->report_string = repstr;
|
||||
field->sort_value = (const void *) field->report_string;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_field_int(struct dm_report *rh,
|
||||
struct dm_report_field *field, const int *data)
|
||||
{
|
||||
const int value = *data;
|
||||
uint64_t *sortval;
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
|
||||
log_error("dm_report_field_int: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
|
||||
log_error("dm_report_field_int: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(repstr, 12, "%d", value) < 0) {
|
||||
log_error("dm_report_field_int: int too big: %d", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sortval = (const uint64_t) value;
|
||||
field->sort_value = sortval;
|
||||
field->report_string = repstr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_field_uint32(struct dm_report *rh,
|
||||
struct dm_report_field *field, const uint32_t *data)
|
||||
{
|
||||
const uint32_t value = *data;
|
||||
uint64_t *sortval;
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_zalloc(rh->mem, 12))) {
|
||||
log_error("dm_report_field_uint32: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
|
||||
log_error("dm_report_field_uint32: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(repstr, 11, "%u", value) < 0) {
|
||||
log_error("dm_report_field_uint32: uint32 too big: %u", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sortval = (const uint64_t) value;
|
||||
field->sort_value = sortval;
|
||||
field->report_string = repstr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_field_int32(struct dm_report *rh,
|
||||
struct dm_report_field *field, const int32_t *data)
|
||||
{
|
||||
const int32_t value = *data;
|
||||
uint64_t *sortval;
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
|
||||
log_error("dm_report_field_int32: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
|
||||
log_error("dm_report_field_int32: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(repstr, 12, "%d", value) < 0) {
|
||||
log_error("dm_report_field_int32: int32 too big: %d", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sortval = (const uint64_t) value;
|
||||
field->sort_value = sortval;
|
||||
field->report_string = repstr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_field_uint64(struct dm_report *rh,
|
||||
struct dm_report_field *field, const uint64_t *data)
|
||||
{
|
||||
const int value = *data;
|
||||
uint64_t *sortval;
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_zalloc(rh->mem, 22))) {
|
||||
log_error("dm_report_field_uint64: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
|
||||
log_error("dm_report_field_uint64: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(repstr, 21, "%d", value) < 0) {
|
||||
log_error("dm_report_field_uint64: uint64 too big: %d", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sortval = (const uint64_t) value;
|
||||
field->sort_value = sortval;
|
||||
field->report_string = repstr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper functions for custom report functions
|
||||
*/
|
||||
void dm_report_field_set_value(struct dm_report_field *field, const void *value, const void *sortvalue)
|
||||
{
|
||||
field->report_string = (const char *) value;
|
||||
field->sort_value = sortvalue ? : value;
|
||||
}
|
||||
|
||||
/*
|
||||
* show help message
|
||||
*/
|
||||
static void _display_fields(struct dm_report *rh)
|
||||
{
|
||||
uint32_t f;
|
||||
const struct dm_report_object_type *type;
|
||||
const char *desc, *last_desc = "";
|
||||
size_t id_len = 0;
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++)
|
||||
if (strlen(rh->fields[f].id) > id_len)
|
||||
id_len = strlen(rh->fields[f].id);
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++) {
|
||||
if ((type = _find_type(rh, rh->fields[f].type)) && type->desc)
|
||||
desc = type->desc;
|
||||
else
|
||||
desc = " ";
|
||||
if (desc != last_desc) {
|
||||
if (*last_desc)
|
||||
log_print(" ");
|
||||
log_print("%s Fields", desc);
|
||||
log_print("%*.*s", (int) strlen(desc) + 7,
|
||||
(int) strlen(desc) + 7,
|
||||
"------------------------------------------");
|
||||
|
||||
}
|
||||
|
||||
/* FIXME Add line-wrapping at terminal width (or 80 cols) */
|
||||
log_print(" %-*s - %s", (int) id_len, rh->fields[f].id, rh->fields[f].desc);
|
||||
last_desc = desc;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise report handle
|
||||
*/
|
||||
static int _copy_field(struct dm_report *rh, struct field_properties *dest,
|
||||
uint32_t field_num)
|
||||
{
|
||||
dest->field_num = field_num;
|
||||
dest->width = rh->fields[field_num].width;
|
||||
dest->flags = rh->fields[field_num].flags & DM_REPORT_FIELD_MASK;
|
||||
|
||||
/* set object type method */
|
||||
dest->type = _find_type(rh, rh->fields[field_num].type);
|
||||
if (!dest->type) {
|
||||
log_error("dm_report: field not match: %s",
|
||||
rh->fields[field_num].id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct field_properties * _add_field(struct dm_report *rh,
|
||||
uint32_t field_num, uint32_t flags)
|
||||
{
|
||||
struct field_properties *fp;
|
||||
|
||||
rh->report_types |= rh->fields[field_num].type;
|
||||
|
||||
if (!(fp = dm_pool_zalloc(rh->mem, sizeof(struct field_properties)))) {
|
||||
log_error("dm_report: struct field_properties allocation "
|
||||
"failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_copy_field(rh, fp, field_num)) {
|
||||
stack;
|
||||
dm_pool_free(rh->mem, fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fp->flags |= flags;
|
||||
|
||||
/*
|
||||
* Place hidden fields at the front so list_end() will
|
||||
* tell us when we've reached the last visible field.
|
||||
*/
|
||||
if (fp->flags & FLD_HIDDEN)
|
||||
list_add_h(&rh->field_props, &fp->list);
|
||||
else
|
||||
list_add(&rh->field_props, &fp->list);
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare name1 against name2 or prefix plus name2
|
||||
* name2 is not necessarily null-terminated.
|
||||
* len2 is the length of name2.
|
||||
*/
|
||||
static int _is_same_field(const char *name1, const char *name2,
|
||||
size_t len2, const char *prefix)
|
||||
{
|
||||
size_t prefix_len;
|
||||
|
||||
/* Exact match? */
|
||||
if (!strncasecmp(name1, name2, len2) && strlen(name1) == len2)
|
||||
return 1;
|
||||
|
||||
/* Match including prefix? */
|
||||
prefix_len = strlen(prefix);
|
||||
if (!strncasecmp(prefix, name1, prefix_len) &&
|
||||
!strncasecmp(name1 + prefix_len, name2, len2) &&
|
||||
strlen(name1) == prefix_len + len2)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _field_match(struct dm_report *rh, const char *field, size_t flen)
|
||||
{
|
||||
uint32_t f;
|
||||
|
||||
if (!flen)
|
||||
return 0;
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++)
|
||||
if (_is_same_field(rh->fields[f].id, field, flen,
|
||||
rh->field_prefix))
|
||||
return _add_field(rh, f, 0) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _add_sort_key(struct dm_report *rh, uint32_t field_num,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct field_properties *fp, *found = NULL;
|
||||
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
if (fp->field_num == field_num) {
|
||||
found = fp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && !(found = _add_field(rh, field_num, FLD_HIDDEN)))
|
||||
return_0;
|
||||
|
||||
if (found->flags & FLD_SORT_KEY) {
|
||||
log_error("dm_report: Ignoring duplicate sort field: %s",
|
||||
rh->fields[field_num].id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
found->flags |= FLD_SORT_KEY;
|
||||
found->sort_posn = rh->keys_count++;
|
||||
found->flags |= flags;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _key_match(struct dm_report *rh, const char *key, size_t len)
|
||||
{
|
||||
uint32_t f;
|
||||
uint32_t flags;
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
if (*key == '+') {
|
||||
key++;
|
||||
len--;
|
||||
flags = FLD_ASCENDING;
|
||||
} else if (*key == '-') {
|
||||
key++;
|
||||
len--;
|
||||
flags = FLD_DESCENDING;
|
||||
} else
|
||||
flags = FLD_ASCENDING;
|
||||
|
||||
if (!len) {
|
||||
log_error("dm_report: Missing sort field name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++)
|
||||
if (_is_same_field(rh->fields[f].id, key, len,
|
||||
rh->field_prefix))
|
||||
return _add_sort_key(rh, f, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _parse_options(struct dm_report *rh, const char *format)
|
||||
{
|
||||
const char *ws; /* Word start */
|
||||
const char *we = format; /* Word end */
|
||||
|
||||
while (*we) {
|
||||
/* Allow consecutive commas */
|
||||
while (*we && *we == ',')
|
||||
we++;
|
||||
|
||||
/* start of the field name */
|
||||
ws = we;
|
||||
while (*we && *we != ',')
|
||||
we++;
|
||||
|
||||
if (!_field_match(rh, ws, (size_t) (we - ws))) {
|
||||
_display_fields(rh);
|
||||
log_print(" ");
|
||||
if (strcasecmp(ws, "help") && strcmp(ws, "?"))
|
||||
log_error("Unrecognised field: %.*s",
|
||||
(int) (we - ws), ws);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _parse_keys(struct dm_report *rh, const char *keys)
|
||||
{
|
||||
const char *ws; /* Word start */
|
||||
const char *we = keys; /* Word end */
|
||||
|
||||
while (*we) {
|
||||
/* Allow consecutive commas */
|
||||
while (*we && *we == ',')
|
||||
we++;
|
||||
ws = we;
|
||||
while (*we && *we != ',')
|
||||
we++;
|
||||
if (!_key_match(rh, ws, (size_t) (we - ws))) {
|
||||
log_error("dm_report: Unrecognised field: %.*s",
|
||||
(int) (we - ws), ws);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dm_report *dm_report_init(uint32_t *report_types,
|
||||
const struct dm_report_object_type *types,
|
||||
const struct dm_report_field_type *fields,
|
||||
const char *output_fields,
|
||||
const char *output_separator,
|
||||
uint32_t output_flags,
|
||||
const char *sort_keys,
|
||||
void *private)
|
||||
{
|
||||
struct dm_report *rh;
|
||||
const struct dm_report_object_type *type;
|
||||
|
||||
if (!(rh = dm_malloc(sizeof(*rh)))) {
|
||||
log_error("dm_report_init: dm_malloc failed");
|
||||
return 0;
|
||||
}
|
||||
memset(rh, 0, sizeof(*rh));
|
||||
|
||||
/*
|
||||
* rh->report_types is updated in _parse_options() and _parse_keys()
|
||||
* to contain all types corresponding to the fields specified by
|
||||
* options or keys.
|
||||
*/
|
||||
if (report_types)
|
||||
rh->report_types = *report_types;
|
||||
|
||||
rh->separator = output_separator;
|
||||
rh->fields = fields;
|
||||
rh->types = types;
|
||||
rh->private = private;
|
||||
|
||||
rh->flags |= output_flags & DM_REPORT_OUTPUT_MASK;
|
||||
|
||||
if (output_flags & DM_REPORT_OUTPUT_BUFFERED)
|
||||
rh->flags |= RH_SORT_REQUIRED;
|
||||
|
||||
list_init(&rh->field_props);
|
||||
list_init(&rh->rows);
|
||||
|
||||
if ((type = _find_type(rh, rh->report_types)) && type->prefix)
|
||||
rh->field_prefix = type->prefix;
|
||||
else
|
||||
rh->field_prefix = "";
|
||||
|
||||
if (!(rh->mem = dm_pool_create("report", 10 * 1024))) {
|
||||
log_error("dm_report_init: allocation of memory pool failed");
|
||||
dm_free(rh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Generate list of fields for output based on format string & flags */
|
||||
if (!_parse_options(rh, output_fields)) {
|
||||
dm_report_free(rh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_parse_keys(rh, sort_keys)) {
|
||||
dm_report_free(rh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return updated types value for further compatility check by caller */
|
||||
if (report_types)
|
||||
*report_types = rh->report_types;
|
||||
|
||||
return rh;
|
||||
}
|
||||
|
||||
void dm_report_free(struct dm_report *rh)
|
||||
{
|
||||
dm_pool_destroy(rh->mem);
|
||||
dm_free(rh);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a row of data for an object
|
||||
*/
|
||||
static void * _report_get_field_data(struct dm_report *rh,
|
||||
struct field_properties *fp, void *object)
|
||||
{
|
||||
void *ret = fp->type->data_fn(object);
|
||||
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
return ret + rh->fields[fp->field_num].offset;
|
||||
}
|
||||
|
||||
int dm_report_object(struct dm_report *rh, void *object)
|
||||
{
|
||||
struct field_properties *fp;
|
||||
struct row *row;
|
||||
struct dm_report_field *field;
|
||||
void *data = NULL;
|
||||
|
||||
if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
|
||||
log_error("dm_report_object: struct row allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
row->rh = rh;
|
||||
|
||||
if ((rh->flags & RH_SORT_REQUIRED) &&
|
||||
!(row->sort_fields =
|
||||
dm_pool_zalloc(rh->mem, sizeof(struct dm_report_field *) *
|
||||
rh->keys_count))) {
|
||||
log_error("dm_report_object: "
|
||||
"row sort value structure allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_init(&row->fields);
|
||||
list_add(&rh->rows, &row->list);
|
||||
|
||||
/* For each field to be displayed, call its report_fn */
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
if (!(field = dm_pool_zalloc(rh->mem, sizeof(*field)))) {
|
||||
log_error("dm_report_object: "
|
||||
"struct dm_report_field allocation failed");
|
||||
return 0;
|
||||
}
|
||||
field->props = fp;
|
||||
|
||||
data = _report_get_field_data(rh, fp, object);
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
if (!rh->fields[fp->field_num].report_fn(rh, rh->mem,
|
||||
field, data,
|
||||
rh->private)) {
|
||||
log_error("dm_report_object: "
|
||||
"report function failed for field %s",
|
||||
rh->fields[fp->field_num].id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((strlen(field->report_string) > field->props->width))
|
||||
field->props->width = strlen(field->report_string);
|
||||
|
||||
if ((rh->flags & RH_SORT_REQUIRED) &&
|
||||
(field->props->flags & FLD_SORT_KEY)) {
|
||||
(*row->sort_fields)[field->props->sort_posn] = field;
|
||||
}
|
||||
list_add(&row->fields, &field->list);
|
||||
}
|
||||
|
||||
if (!(rh->flags & DM_REPORT_OUTPUT_BUFFERED))
|
||||
return dm_report_output(rh);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print row of headings
|
||||
*/
|
||||
static int _report_headings(struct dm_report *rh)
|
||||
{
|
||||
struct field_properties *fp;
|
||||
const char *heading;
|
||||
char buf[1024];
|
||||
|
||||
if (rh->flags & RH_HEADINGS_PRINTED)
|
||||
return 1;
|
||||
|
||||
rh->flags |= RH_HEADINGS_PRINTED;
|
||||
|
||||
if (!(rh->flags & DM_REPORT_OUTPUT_HEADINGS))
|
||||
return 1;
|
||||
|
||||
if (!dm_pool_begin_object(rh->mem, 128)) {
|
||||
log_error("dm_report: "
|
||||
"dm_pool_begin_object failed for headings");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* First heading line */
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
if (fp->flags & FLD_HIDDEN)
|
||||
continue;
|
||||
|
||||
heading = rh->fields[fp->field_num].heading;
|
||||
if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
|
||||
fp->width, fp->width, heading) < 0) {
|
||||
log_error("dm_report: snprintf heading failed");
|
||||
goto bad;
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, buf, fp->width)) {
|
||||
log_error("dm_report: Failed to generate report headings for printing");
|
||||
goto bad;
|
||||
}
|
||||
} else if (!dm_pool_grow_object(rh->mem, heading,
|
||||
strlen(heading))) {
|
||||
log_error("dm_report: Failed to generate report headings for printing");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!list_end(&rh->field_props, &fp->list))
|
||||
if (!dm_pool_grow_object(rh->mem, rh->separator,
|
||||
strlen(rh->separator))) {
|
||||
log_error("dm_report: Failed to generate report headings for printing");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
|
||||
log_error("dm_report: Failed to generate report headings for printing");
|
||||
goto bad;
|
||||
}
|
||||
log_print("%s", (char *) dm_pool_end_object(rh->mem));
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
dm_pool_abandon_object(rh->mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort rows of data
|
||||
*/
|
||||
static int _row_compare(const void *a, const void *b)
|
||||
{
|
||||
const struct row *rowa = *(const struct row **) a;
|
||||
const struct row *rowb = *(const struct row **) b;
|
||||
const struct dm_report_field *sfa, *sfb;
|
||||
uint32_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < rowa->rh->keys_count; cnt++) {
|
||||
sfa = (*rowa->sort_fields)[cnt];
|
||||
sfb = (*rowb->sort_fields)[cnt];
|
||||
if (sfa->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) {
|
||||
const uint64_t numa =
|
||||
*(const uint64_t *) sfa->sort_value;
|
||||
const uint64_t numb =
|
||||
*(const uint64_t *) sfb->sort_value;
|
||||
|
||||
if (numa == numb)
|
||||
continue;
|
||||
|
||||
if (sfa->props->flags & FLD_ASCENDING) {
|
||||
return (numa > numb) ? 1 : -1;
|
||||
} else { /* FLD_DESCENDING */
|
||||
return (numa < numb) ? 1 : -1;
|
||||
}
|
||||
} else { /* DM_REPORT_FIELD_TYPE_STRING */
|
||||
const char *stra = (const char *) sfa->sort_value;
|
||||
const char *strb = (const char *) sfb->sort_value;
|
||||
int cmp = strcmp(stra, strb);
|
||||
|
||||
if (!cmp)
|
||||
continue;
|
||||
|
||||
if (sfa->props->flags & FLD_ASCENDING) {
|
||||
return (cmp > 0) ? 1 : -1;
|
||||
} else { /* FLD_DESCENDING */
|
||||
return (cmp < 0) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0; /* Identical */
|
||||
}
|
||||
|
||||
static int _sort_rows(struct dm_report *rh)
|
||||
{
|
||||
struct row *(*rows)[];
|
||||
uint32_t count = 0;
|
||||
struct row *row;
|
||||
|
||||
if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) *
|
||||
list_size(&rh->rows)))) {
|
||||
log_error("dm_report: sort array allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate_items(row, &rh->rows)
|
||||
(*rows)[count++] = row;
|
||||
|
||||
qsort(rows, count, sizeof(**rows), _row_compare);
|
||||
|
||||
list_init(&rh->rows);
|
||||
while (count--)
|
||||
list_add_h(&rh->rows, &(*rows)[count]->list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Produce report output
|
||||
*/
|
||||
int dm_report_output(struct dm_report *rh)
|
||||
{
|
||||
struct list *fh, *rowh, *ftmp, *rtmp;
|
||||
struct row *row = NULL;
|
||||
struct dm_report_field *field;
|
||||
const char *repstr;
|
||||
char buf[4096];
|
||||
int32_t width;
|
||||
uint32_t align;
|
||||
|
||||
if (list_empty(&rh->rows))
|
||||
return 1;
|
||||
|
||||
/* Sort rows */
|
||||
if ((rh->flags & RH_SORT_REQUIRED))
|
||||
_sort_rows(rh);
|
||||
|
||||
/* If headings not printed yet, calculate field widths and print them */
|
||||
if (!(rh->flags & RH_HEADINGS_PRINTED))
|
||||
_report_headings(rh);
|
||||
|
||||
/* Print and clear buffer */
|
||||
list_iterate_safe(rowh, rtmp, &rh->rows) {
|
||||
if (!dm_pool_begin_object(rh->mem, 512)) {
|
||||
log_error("dm_report: Unable to allocate output line");
|
||||
return 0;
|
||||
}
|
||||
row = list_item(rowh, struct row);
|
||||
list_iterate_safe(fh, ftmp, &row->fields) {
|
||||
field = list_item(fh, struct dm_report_field);
|
||||
if (field->props->flags & FLD_HIDDEN)
|
||||
continue;
|
||||
|
||||
repstr = field->report_string;
|
||||
width = field->props->width;
|
||||
if (!(rh->flags & DM_REPORT_OUTPUT_ALIGNED)) {
|
||||
if (!dm_pool_grow_object(rh->mem, repstr,
|
||||
strlen(repstr))) {
|
||||
log_error("dm_report: Unable to extend output line");
|
||||
goto bad;
|
||||
}
|
||||
} else {
|
||||
if (!(align = field->props->flags & DM_REPORT_FIELD_ALIGN_MASK))
|
||||
align = (field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ?
|
||||
DM_REPORT_FIELD_ALIGN_RIGHT : DM_REPORT_FIELD_ALIGN_LEFT;
|
||||
if (align & DM_REPORT_FIELD_ALIGN_LEFT) {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
|
||||
width, width, repstr) < 0) {
|
||||
log_error("dm_report: left-aligned snprintf() failed");
|
||||
goto bad;
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, buf, width)) {
|
||||
log_error("dm_report: Unable to extend output line");
|
||||
goto bad;
|
||||
}
|
||||
} else if (align & DM_REPORT_FIELD_ALIGN_RIGHT) {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%*.*s",
|
||||
width, width, repstr) < 0) {
|
||||
log_error("dm_report: right-aligned snprintf() failed");
|
||||
goto bad;
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, buf, width)) {
|
||||
log_error("dm_report: Unable to extend output line");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!list_end(&row->fields, fh))
|
||||
if (!dm_pool_grow_object(rh->mem, rh->separator,
|
||||
strlen(rh->separator))) {
|
||||
log_error("dm_report: Unable to extend output line");
|
||||
goto bad;
|
||||
}
|
||||
list_del(&field->list);
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
|
||||
log_error("dm_report: Unable to terminate output line");
|
||||
goto bad;
|
||||
}
|
||||
log_print("%s", (char *) dm_pool_end_object(rh->mem));
|
||||
list_del(&row->list);
|
||||
}
|
||||
|
||||
if (row)
|
||||
dm_pool_free(rh->mem, row);
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
dm_pool_abandon_object(rh->mem);
|
||||
return 0;
|
||||
}
|
||||
@@ -37,7 +37,8 @@ static int _isword(int c)
|
||||
* Split buffer into NULL-separated words in argv.
|
||||
* Returns number of words.
|
||||
*/
|
||||
int dm_split_words(char *buffer, unsigned max, unsigned ignore_comments,
|
||||
int dm_split_words(char *buffer, unsigned max,
|
||||
unsigned ignore_comments __attribute((unused)),
|
||||
char **argv)
|
||||
{
|
||||
unsigned arg;
|
||||
@@ -116,7 +117,7 @@ int dm_snprintf(char *buf, size_t bufsize, const char *format, ...)
|
||||
n = vsnprintf(buf, bufsize, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (n < 0 || (n > bufsize - 1))
|
||||
if (n < 0 || ((unsigned) n + 1 > bufsize))
|
||||
return -1;
|
||||
|
||||
return n;
|
||||
@@ -129,7 +130,7 @@ char *dm_basename(const char *path)
|
||||
return p ? p + 1 : (char *) path;
|
||||
}
|
||||
|
||||
int dm_saprintf(char **result, const char *format, ...)
|
||||
int dm_asprintf(char **result, const char *format, ...)
|
||||
{
|
||||
int n, ok = 0, size = 32;
|
||||
va_list ap;
|
||||
|
||||
@@ -20,9 +20,14 @@
|
||||
|
||||
char *dm_strdup_aux(const char *str, const char *file, int line)
|
||||
{
|
||||
char *ret = dm_malloc_aux_debug(strlen(str) + 1, file, line);
|
||||
char *ret;
|
||||
|
||||
if (ret)
|
||||
if (!str) {
|
||||
log_error("Internal error: dm_strdup called with NULL pointer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((ret = dm_malloc_aux_debug(strlen(str) + 1, file, line)))
|
||||
strcpy(ret, str);
|
||||
|
||||
return ret;
|
||||
@@ -226,7 +231,8 @@ void dm_bounds_check_debug(void)
|
||||
}
|
||||
}
|
||||
|
||||
void *dm_malloc_aux(size_t s, const char *file, int line)
|
||||
void *dm_malloc_aux(size_t s, const char *file __attribute((unused)),
|
||||
int line __attribute((unused)))
|
||||
{
|
||||
if (s > 50000000) {
|
||||
log_error("Huge memory allocation (size %" PRIsize_t
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_DBG_MALLOC_H
|
||||
#define _LVM_DBG_MALLOC_H
|
||||
#ifndef _DM_DBG_MALLOC_H
|
||||
#define _DM_DBG_MALLOC_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_POOL_H
|
||||
#define _LVM_POOL_H
|
||||
#ifndef _DM_POOL_H
|
||||
#define _DM_POOL_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
* 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
|
||||
@@ -14,9 +14,9 @@
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "matcher.h"
|
||||
#include "parse_rx.h"
|
||||
#include "ttree.h"
|
||||
#include "assert.h"
|
||||
|
||||
struct dfa_state {
|
||||
int final;
|
||||
@@ -29,7 +29,7 @@ struct state_queue {
|
||||
struct state_queue *next;
|
||||
};
|
||||
|
||||
struct matcher { /* Instance variables for the lexer */
|
||||
struct dm_regex { /* Instance variables for the lexer */
|
||||
struct dfa_state *start;
|
||||
unsigned num_nodes;
|
||||
int nodes_entered;
|
||||
@@ -52,7 +52,7 @@ static int _count_nodes(struct rx_node *rx)
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _fill_table(struct matcher *m, struct rx_node *rx)
|
||||
static void _fill_table(struct dm_regex *m, struct rx_node *rx)
|
||||
{
|
||||
assert((rx->type != OR) || (rx->left && rx->right));
|
||||
|
||||
@@ -65,7 +65,7 @@ static void _fill_table(struct matcher *m, struct rx_node *rx)
|
||||
m->nodes[m->nodes_entered++] = rx;
|
||||
}
|
||||
|
||||
static void _create_bitsets(struct matcher *m)
|
||||
static void _create_bitsets(struct dm_regex *m)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -77,7 +77,7 @@ static void _create_bitsets(struct matcher *m)
|
||||
}
|
||||
}
|
||||
|
||||
static void _calc_functions(struct matcher *m)
|
||||
static void _calc_functions(struct dm_regex *m)
|
||||
{
|
||||
int i, j, final = 1;
|
||||
struct rx_node *rx, *c1, *c2;
|
||||
@@ -189,7 +189,7 @@ static struct state_queue *_create_state_queue(struct dm_pool *mem,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _calc_states(struct matcher *m, struct rx_node *rx)
|
||||
static int _calc_states(struct dm_regex *m, struct rx_node *rx)
|
||||
{
|
||||
unsigned iwidth = (m->num_nodes / DM_BITS_PER_INT) + 1;
|
||||
struct ttree *tt = ttree_create(m->scratch, iwidth);
|
||||
@@ -263,43 +263,38 @@ static int _calc_states(struct matcher *m, struct rx_node *rx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct matcher *matcher_create(struct dm_pool *mem, const char **patterns,
|
||||
unsigned num)
|
||||
struct dm_regex *dm_regex_create(struct dm_pool *mem, const char **patterns,
|
||||
unsigned num_patterns)
|
||||
{
|
||||
char *all, *ptr;
|
||||
int i;
|
||||
size_t len = 0;
|
||||
struct rx_node *rx;
|
||||
struct dm_pool *scratch = dm_pool_create("regex matcher", 10 * 1024);
|
||||
struct matcher *m;
|
||||
struct dm_regex *m;
|
||||
|
||||
if (!scratch) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
if (!scratch)
|
||||
return_NULL;
|
||||
|
||||
if (!(m = dm_pool_alloc(mem, sizeof(*m)))) {
|
||||
stack;
|
||||
dm_pool_destroy(scratch);
|
||||
return NULL;
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
memset(m, 0, sizeof(*m));
|
||||
|
||||
/* join the regexps together, delimiting with zero */
|
||||
for (i = 0; i < num; i++)
|
||||
for (i = 0; i < num_patterns; i++)
|
||||
len += strlen(patterns[i]) + 8;
|
||||
|
||||
ptr = all = dm_pool_alloc(scratch, len + 1);
|
||||
|
||||
if (!all) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!all)
|
||||
goto_bad;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
for (i = 0; i < num_patterns; i++) {
|
||||
ptr += sprintf(ptr, "(.*(%s)%c)", patterns[i], TARGET_TRANS);
|
||||
if (i < (num - 1))
|
||||
if (i < (num_patterns - 1))
|
||||
*ptr++ = '|';
|
||||
}
|
||||
|
||||
@@ -314,10 +309,8 @@ struct matcher *matcher_create(struct dm_pool *mem, const char **patterns,
|
||||
m->num_nodes = _count_nodes(rx);
|
||||
m->nodes = dm_pool_alloc(scratch, sizeof(*m->nodes) * m->num_nodes);
|
||||
|
||||
if (!m->nodes) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!m->nodes)
|
||||
goto_bad;
|
||||
|
||||
_fill_table(m, rx);
|
||||
_create_bitsets(m);
|
||||
@@ -330,7 +323,7 @@ struct matcher *matcher_create(struct dm_pool *mem, const char **patterns,
|
||||
|
||||
bad:
|
||||
dm_pool_destroy(scratch);
|
||||
dm_pool_destroy(mem);
|
||||
dm_pool_free(mem, m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -345,16 +338,16 @@ static struct dfa_state *_step_matcher(int c, struct dfa_state *cs, int *r)
|
||||
return cs;
|
||||
}
|
||||
|
||||
int matcher_run(struct matcher *m, const char *b)
|
||||
int dm_regex_match(struct dm_regex *regex, const char *s)
|
||||
{
|
||||
struct dfa_state *cs = m->start;
|
||||
struct dfa_state *cs = regex->start;
|
||||
int r = 0;
|
||||
|
||||
if (!(cs = _step_matcher(HAT_CHAR, cs, &r)))
|
||||
goto out;
|
||||
|
||||
for (; *b; b++)
|
||||
if (!(cs = _step_matcher(*b, cs, &r)))
|
||||
for (; *s; s++)
|
||||
if (!(cs = _step_matcher(*s, cs, &r)))
|
||||
goto out;
|
||||
|
||||
_step_matcher(DOLLAR_CHAR, cs, &r);
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
* 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
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
* 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
|
||||
@@ -13,8 +13,8 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_PARSE_REGEX_H
|
||||
#define _LVM_PARSE_REGEX_H
|
||||
#ifndef _DM_PARSE_REGEX_H
|
||||
#define _DM_PARSE_REGEX_H
|
||||
|
||||
enum {
|
||||
CAT,
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
* 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
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
* 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
|
||||
@@ -13,8 +13,8 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_TTREE_H
|
||||
#define _LVM_TTREE_H
|
||||
#ifndef _DM_TTREE_H
|
||||
#define _DM_TTREE_H
|
||||
|
||||
struct ttree;
|
||||
|
||||
@@ -56,7 +56,7 @@ endif
|
||||
|
||||
.SUFFIXES: .c .d .o .so .a .po .pot .mo .dylib
|
||||
|
||||
CFLAGS += -fPIC -Wall -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -Wmissing-noreturn
|
||||
CFLAGS += -fPIC -Wall -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -Wmissing-noreturn -Wformat-security
|
||||
|
||||
#CFLAGS += -W -Wconversion -Wpointer-arith -Wredundant-decls -Wbad-function-cast -Wcast-qual
|
||||
#CFLAGS += -pedantic -std=gnu99
|
||||
@@ -94,7 +94,7 @@ STRIP=
|
||||
LIB_VERSION := $(shell cat $(top_srcdir)/VERSION | \
|
||||
awk -F '.' '{printf "%s.%s",$$1,$$2}')
|
||||
|
||||
INCLUDES += -I. -I$(top_srcdir)/include
|
||||
INCLUDES += -I$(top_srcdir)/include
|
||||
|
||||
ifneq ("@DMDIR@", "")
|
||||
INCLUDES += -I@DMDIR@/include
|
||||
|
||||
@@ -20,7 +20,7 @@ MAN5=lvm.conf.5
|
||||
MAN8=lvchange.8 lvconvert.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 \
|
||||
lvmchange.8 lvmdiskscan.8 lvmdump.8 \
|
||||
lvreduce.8 lvremove.8 lvrename.8 lvresize.8 lvs.8 \
|
||||
lvscan.8 pvchange.8 pvcreate.8 pvdisplay.8 pvmove.8 pvremove.8 \
|
||||
lvscan.8 pvchange.8 pvck.8 pvcreate.8 pvdisplay.8 pvmove.8 pvremove.8 \
|
||||
pvresize.8 pvs.8 pvscan.8 vgcfgbackup.8 vgcfgrestore.8 vgchange.8 \
|
||||
vgck.8 vgcreate.8 vgconvert.8 vgdisplay.8 vgexport.8 vgextend.8 \
|
||||
vgimport.8 vgmerge.8 vgmknodes.8 vgreduce.8 vgremove.8 vgrename.8 \
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
dmsetup \- low level logical volume management
|
||||
.SH SYNOPSIS
|
||||
.ad l
|
||||
.B dmsetup help
|
||||
.I [-c|-C|--columns]
|
||||
.br
|
||||
.B dmsetup create
|
||||
.I device_name [-u uuid] [--notable | --table <table> | table_file]
|
||||
.br
|
||||
@@ -33,21 +36,25 @@ dmsetup \- low level logical volume management
|
||||
.B dmsetup message
|
||||
.I device_name sector message
|
||||
.br
|
||||
.B dmsetup ls [--target target_type] [--exec command] [--tree [-o options]]
|
||||
.B dmsetup ls
|
||||
.I [--target target_type] [--exec command] [--tree [-o options]]
|
||||
.br
|
||||
.B dmsetup info
|
||||
.I [device_name]
|
||||
.br
|
||||
.B dmsetup info -c|-C|--columns [--noheadings] [-o name]
|
||||
.B dmsetup info -c|-C|--columns
|
||||
.I [--noheadings] [--separator separator] [-o fields] [-O|--sort sort_fields]
|
||||
.I [device_name]
|
||||
.br
|
||||
.B dmsetup deps
|
||||
.I [device_name]
|
||||
.br
|
||||
.B dmsetup status [--target target_type]
|
||||
.B dmsetup status
|
||||
.I [--target target_type]
|
||||
.I [device_name]
|
||||
.br
|
||||
.B dmsetup table [--target target_type]
|
||||
.B dmsetup table
|
||||
.I [--target target_type]
|
||||
.I [device_name]
|
||||
.br
|
||||
.B dmsetup wait
|
||||
@@ -103,7 +110,7 @@ Tell the kernel not to supply the open reference count for the device.
|
||||
When creating a device, don't load any table.
|
||||
.IP \fB-o|--options
|
||||
.br
|
||||
Specify which fields to display. Only \fB-o\ name\fP is supported.
|
||||
Specify which fields to display.
|
||||
.IP \fB-r|--readonly
|
||||
.br
|
||||
Set the table being loaded read-only.
|
||||
@@ -136,6 +143,11 @@ See below for information on the table format.
|
||||
.br
|
||||
Outputs a list of (major, minor) pairs for devices referenced by the
|
||||
live table for the specified device.
|
||||
.IP \fBhelp
|
||||
.I [-c|-C|--columns]
|
||||
.br
|
||||
Outputs a summary of the commands available, optionally including
|
||||
the list of report fields.
|
||||
.IP \fBinfo
|
||||
.I [device_name]
|
||||
.br
|
||||
@@ -154,6 +166,17 @@ Outputs some brief information about the device in the form:
|
||||
Number of targets in the live table
|
||||
.br
|
||||
UUID
|
||||
.IP \fBinfo -c|-C|--columns
|
||||
.I [--noheadings] [--separator separator] [-o fields] [-O|--sort sort_fields]
|
||||
.I [device_name]
|
||||
.br
|
||||
Output you can customise.
|
||||
Fields are comma-separated and chosen from the following list:
|
||||
name, major, minor, attr, open, segments, events, uuid.
|
||||
Attributes are: (L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.
|
||||
Precede the list with '+' to append
|
||||
to the default selection of columns instead of replacing it.
|
||||
Precede any sort_field with - for a reverse sort on that column.
|
||||
.IP \fBls
|
||||
.I [--target target_type]
|
||||
.I [--exec command]
|
||||
|
||||
@@ -12,7 +12,7 @@ lvchange \- change attributes of a logical volume
|
||||
[\-\-ignorelockingfailure]
|
||||
[\-\-monitor {y|n}]
|
||||
[\-M/\-\-persistent y/n] [\-\-minor minor]
|
||||
[\-P/\-\-partial y/n]
|
||||
[\-P/\-\-partial]
|
||||
[\-p/\-\-permission r/w] [\-r/\-\-readahead ReadAheadSectors]
|
||||
[\-\-refresh]
|
||||
[\-t/\-\-test]
|
||||
|
||||
@@ -194,6 +194,7 @@ All tools return a status code of zero on success or non-zero on failure.
|
||||
.BR lvs (8),
|
||||
.BR lvscan (8),
|
||||
.BR pvchange (8),
|
||||
.BR pvck (8),
|
||||
.BR pvcreate (8),
|
||||
.BR pvdisplay (8),
|
||||
.BR pvmove (8),
|
||||
|
||||
@@ -81,6 +81,11 @@ LVM physical volumes.
|
||||
Devices in directories outside this hierarchy will be ignored.
|
||||
Defaults to "/dev".
|
||||
.IP
|
||||
\fBpreferred_names\fP \(em List of patterns compared in turn against
|
||||
all the pathnames referencing the same device in in the scanned directories.
|
||||
The pathname that matches the earliest pattern in the list is the
|
||||
one used in any output.
|
||||
.IP
|
||||
\fBfilter\fP \(em List of patterns to apply to devices found by a scan.
|
||||
Patterns are regular expressions delimited by any character and preceded
|
||||
by \fBa\fP (for accept) or \fBr\fP (for reject). The list is traversed
|
||||
@@ -95,8 +100,8 @@ pattern it is rejected; otherwise it is accepted.
|
||||
As an example, to ignore /dev/cdrom you could use:
|
||||
\fBdevices { filter=["r|cdrom|"] }\fP
|
||||
.IP
|
||||
\fBcache\fP \(em Persistent filter cache file.
|
||||
Defaults to "/etc/lvm/.cache".
|
||||
\fBcache_dir\fP \(em Persistent filter cache file directory.
|
||||
Defaults to "/etc/lvm/cache".
|
||||
.IP
|
||||
\fBwrite_cache_state\fP \(em Set to 0 to disable the writing out of the
|
||||
persistent filter cache file when \fBlvm\fP exits.
|
||||
@@ -364,9 +369,9 @@ understand how things work: to make changes you should always use
|
||||
the tools as normal, or else vgcfgbackup, edit backup, vgcfgrestore.
|
||||
.SH FILES
|
||||
.I /etc/lvm/lvm.conf
|
||||
.I /etc/lvm/.cache
|
||||
.I /etc/lvm/archive
|
||||
.I /etc/lvm/backup
|
||||
.I /etc/lvm/cache/.cache
|
||||
.I /var/lock/lvm
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
|
||||
@@ -35,11 +35,13 @@ lv_uuid, lv_name, lv_attr, lv_major, lv_minor, lv_kernel_major, lv_kernel_minor,
|
||||
lv_size, seg_count, origin, snap_percent,
|
||||
copy_percent, move_pv, lv_tags,
|
||||
segtype, stripes,
|
||||
stripesize, chunksize, seg_start, seg_size, seg_tags, devices.
|
||||
stripesize, chunksize, seg_start, seg_size, seg_tags, devices,
|
||||
regionsize, mirror_log, modules.
|
||||
.IP
|
||||
With \-\-segments, any "seg_" prefixes are optional; otherwise any "lv_"
|
||||
prefixes are optional. Columns mentioned in \fBvgs (8)\fP
|
||||
can also be chosen.
|
||||
Use \fb-o help\fP to view the full list of fields available.
|
||||
.IP
|
||||
The lv_attr bits are:
|
||||
.RS
|
||||
@@ -49,7 +51,7 @@ invalid (S)napshot, (v)irtual
|
||||
.IP 2 3
|
||||
Permissions: (w)riteable, (r)ead-only
|
||||
.IP 3 3
|
||||
Allocation policy: (c)ontiguous, (n)ormal, (a)nywhere, (i)nherited
|
||||
Allocation policy: (c)ontiguous, c(l)ing, (n)ormal, (a)nywhere, (i)nherited
|
||||
This is capitalised if the volume is currently locked against allocation
|
||||
changes, for example during \fBpvmove\fP (8).
|
||||
.IP 4 3
|
||||
|
||||
33
man/pvck.8
Normal file
33
man/pvck.8
Normal file
@@ -0,0 +1,33 @@
|
||||
.TH PVCK 8 "LVM TOOLS" "Sistina Software UK" \" -*- nroff -*-
|
||||
.SH NAME
|
||||
pvck \- check physical volume metadata
|
||||
.SH SYNOPSIS
|
||||
.B pvck
|
||||
.RB [ \-d | \-\-debug ]
|
||||
.RB [ \-h | \-\-help ]
|
||||
.RB [ \-v | \-\-verbose ]
|
||||
.RB [ \-\-labelsector ]
|
||||
.IR PhysicalVolume " [" PhysicalVolume ...]
|
||||
.SH DESCRIPTION
|
||||
pvck checks physical volume LVM metadata for consistency.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.BR \-\-labelsector " sector"
|
||||
By default, 4 sectors of \fBPhysicalVolume\fP are scanned for an LVM label,
|
||||
starting at sector 0. This parameter allows you to specify a different
|
||||
starting sector for the scan and is useful for recovery situations. For
|
||||
example, suppose the partition table is corrupted or lost on /dev/sda,
|
||||
but you suspect there was an LVM partition at approximately 100 MB. This
|
||||
area of the disk may be scanned by using the \fB--labelsector\fP parameter
|
||||
with a value of 204800 (100 * 1024 * 1024 / 512 = 204800):
|
||||
.sp
|
||||
.BI "pvck --labelsector 204800 /dev/sda"
|
||||
.sp
|
||||
Note that a script can be used with \fB--labelsector\fP to automate the
|
||||
process of finding LVM labels.
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
.BR pvcreate (8),
|
||||
.BR pvscan (8)
|
||||
.BR vgck (8)
|
||||
@@ -5,7 +5,7 @@ pvmove \- move physical extents
|
||||
.B pvmove
|
||||
[\-\-abort]
|
||||
[\-\-alloc AllocationPolicy]
|
||||
[\-\-background]
|
||||
[\-b/\-\-background]
|
||||
[\-d/\-\-debug] [\-h/\-\-help] [\-i/\-\-interval Seconds] [\-v/\-\-verbose]
|
||||
[\-n/\-\-name LogicalVolume]
|
||||
[SourcePhysicalVolume[:PE[-PE]...] [DestinationPhysicalVolume[:PE[-PE]...]...]]
|
||||
@@ -73,7 +73,7 @@ type of on-disk metadata. Metadata can be converted using \fBvgconvert\fP(8).
|
||||
.I \-\-abort
|
||||
Abort any moves in progress.
|
||||
.TP
|
||||
.I \-\-background
|
||||
.I \-b, \-\-background
|
||||
Run the daemon in the background.
|
||||
.TP
|
||||
.I \-i, \-\-interval Seconds
|
||||
|
||||
11
man/pvs.8
11
man/pvs.8
@@ -31,9 +31,16 @@ if processing the output.
|
||||
Comma-separated ordered list of columns. Precede the list with '+' to append
|
||||
to the default selection of columns. Column names are: pv_fmt, pv_uuid,
|
||||
pv_size, dev_size, pv_free, pv_used, pv_name, pv_attr, pv_pe_count,
|
||||
pv_pe_alloc_count, pv_tags.
|
||||
The "pv_" prefix is optional. Columns mentioned in \fBvgs (8)\fP can also
|
||||
pv_pe_alloc_count, pv_tags, pvseg_start, pvseg_size, pe_start.
|
||||
With --segments, any "pvseg_" prefixes are optional; otherwise any
|
||||
"pv_" prefixes are optional. Columns mentioned in \fBvgs (8)\fP can also
|
||||
be chosen. The pv_attr bits are: (a)llocatable and e(x)ported.
|
||||
Use \fb-o help\fP to view the full list of fields available.
|
||||
.TP
|
||||
.I \-\-segments
|
||||
Produces one line of output for each contiguous allocation of space on each
|
||||
Physical Volume, showing the start (pvseg_start) and length (pvseg_size) in
|
||||
units of physical extents.
|
||||
.TP
|
||||
.I \-O, \-\-sort
|
||||
Comma-separated ordered list of columns to sort by. Replaces the default
|
||||
|
||||
@@ -10,6 +10,7 @@ vgchange \- change attributes of a volume group
|
||||
.RB [ \-A | \-\-autobackup " {" y | n }]
|
||||
.RB [ \-a | \-\-available " [e|l] {" y | n }]
|
||||
.RB [ \-\-monitor " {" y | n }]
|
||||
.RB [ \-c | \-\-clustered " {" y | n }]
|
||||
.RB [ \-d | \-\-debug]
|
||||
.RB [ \-\-deltag
|
||||
.IR Tag ]
|
||||
@@ -44,12 +45,12 @@ snapshots should be removed (see
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.BR \-A ", " \-\-autobackup { y | n }
|
||||
.BR \-A ", " \-\-autobackup " " { y | n }
|
||||
Controls automatic backup of metadata after the change. See
|
||||
.B vgcfgbackup (8).
|
||||
Default is yes.
|
||||
.TP
|
||||
.BR \-a ", " \-\-available [e|l] { y | n }
|
||||
.BR \-a ", " \-\-available " " [e|l] { y | n }
|
||||
Controls the availability of the logical volumes in the volume
|
||||
group for input/output.
|
||||
In other words, makes the logical volumes known/unknown to the kernel.
|
||||
@@ -60,6 +61,14 @@ on the local node.
|
||||
Logical volumes with single-host snapshots are always activated
|
||||
exclusively because they can only be used on one node at once.
|
||||
.TP
|
||||
.BR \-c ", " \-\-clustered " " { y | n }
|
||||
If clustered locking is enabled, this indicates whether this
|
||||
Volume Group is shared with other nodes in the cluster or whether
|
||||
it contains only local disks that are not visible on the other nodes.
|
||||
If the cluster infrastructure is unavailable on a particular node at a
|
||||
particular time, you may still be able to use Volume Groups that
|
||||
are not marked as clustered.
|
||||
.TP
|
||||
.BR \-\-monitor " " { y | n }
|
||||
Controls whether or not a mirrored logical volume is monitored by
|
||||
dmeventd, if it is installed.
|
||||
@@ -108,7 +117,7 @@ impact on I/O performance to the logical volume. The smallest PE is 1KB.
|
||||
|
||||
The 2.4 kernel has a limitation of 2TB per block device.
|
||||
.TP
|
||||
.BR \-x ", " \-\-resizeable { y | n }
|
||||
.BR \-x ", " \-\-resizeable " " { y | n }
|
||||
Enables or disables the extension/reduction of this volume group
|
||||
with/by physical volumes.
|
||||
.SH EXAMPLES
|
||||
|
||||
@@ -8,6 +8,7 @@ vgcreate \- create a volume group
|
||||
.RB [ \-\-alloc
|
||||
.IR AllocationPolicy ]
|
||||
.RB [ \-A | \-\-autobackup " {" y | n }]
|
||||
.RB [ \-c | \-\-clustered " {" y | n }]
|
||||
.RB [ \-d | \-\-debug ]
|
||||
.RB [ \-h | \-\-help ]
|
||||
.RB [ \-l | \-\-maxlogicalvolumes
|
||||
@@ -33,6 +34,14 @@ previously configured for LVM with
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.BR \-c ", " \-\-clustered " " { y | n }
|
||||
If clustered locking is enabled, this indicates whether this
|
||||
Volume Group is shared with other nodes in the cluster or whether
|
||||
it contains only local disks that are not visible on the other nodes.
|
||||
If the cluster infrastructure is unavailable on a particular node at a
|
||||
particular time, you may still be able to use Volume Groups that
|
||||
are not marked as clustered.
|
||||
.TP
|
||||
.BR \-l ", " \-\-maxlogicalvolumes " " \fIMaxLogicalVolumes\fR
|
||||
Sets the maximum number of logical volumes allowed in this
|
||||
volume group.
|
||||
|
||||
20
man/vgs.8
20
man/vgs.8
@@ -36,8 +36,24 @@ vg_free_count, max_lv, max_pv, pv_count, lv_count, snap_count, vg_seqno,
|
||||
vg_tags.
|
||||
Any "vg_" prefixes are optional. Columns mentioned in either \fBpvs (8)\fP
|
||||
or \fBlvs (8)\fP can also be chosen, but columns cannot be taken from both
|
||||
at the same time. The vg_attr bits are: (w)riteable, (r)eadonly,
|
||||
resi(z)eable, e(x)ported, (p)artial and (c)lustered.
|
||||
at the same time.
|
||||
Use \fb-o help\fP to view the full list of fields available.
|
||||
.IP
|
||||
The vg_attr bits are:
|
||||
.RS
|
||||
.IP 1 3
|
||||
Permissions: (w)riteable, (r)ead-only
|
||||
.IP 2 3
|
||||
Resi(z)eable
|
||||
.IP 3 3
|
||||
E(x)ported
|
||||
.IP 4 3
|
||||
(p)artial
|
||||
.IP 5 3
|
||||
Allocation policy: (c)ontiguous, c(l)ing, (n)ormal, (a)nywhere, (i)nherited
|
||||
.IP 6 3
|
||||
(c)lustered
|
||||
.RE
|
||||
.TP
|
||||
.I \-O, \-\-sort
|
||||
Comma-separated ordered list of columns to sort by. Replaces the default
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user