mirror of
git://sourceware.org/git/lvm2.git
synced 2025-12-24 16:23:50 +03:00
Compare commits
173 Commits
dm_v1_01_0
...
dm_v1_01_0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
196b8eaad3 | ||
|
|
8e526ba1bf | ||
|
|
19225828d9 | ||
|
|
7e594126be | ||
|
|
d2529e6334 | ||
|
|
97344f18e2 | ||
|
|
33934db629 | ||
|
|
6c6165c9f5 | ||
|
|
853460b20d | ||
|
|
cc4d9676c5 | ||
|
|
1cf1b819f4 | ||
|
|
f916c66d2b | ||
|
|
550aa86b45 | ||
|
|
014e764758 | ||
|
|
d1fc28432b | ||
|
|
879576f0a2 | ||
|
|
69098210be | ||
|
|
99df4f892d | ||
|
|
7bc04fbad3 | ||
|
|
8a74ce578d | ||
|
|
0805e4e5de | ||
|
|
f1060fc88e | ||
|
|
7d3d3d0a3a | ||
|
|
40377032e3 | ||
|
|
b2971edd7d | ||
|
|
c37d723692 | ||
|
|
30f9026e1d | ||
|
|
332286072e | ||
|
|
d6da172a2a | ||
|
|
ebfe584afc | ||
|
|
6250023583 | ||
|
|
6b4f3d63b8 | ||
|
|
56db773a09 | ||
|
|
fc6c472401 | ||
|
|
2cd42a6866 | ||
|
|
36a90c345c | ||
|
|
ef1e82c72c | ||
|
|
88f9534685 | ||
|
|
68254a052a | ||
|
|
2425b3a166 | ||
|
|
5524ed753b | ||
|
|
89711723da | ||
|
|
bed2740ffd | ||
|
|
751d633c3d | ||
|
|
45952cbdf2 | ||
|
|
b355dd7b23 | ||
|
|
48a186f172 | ||
|
|
39dc7ec2ab | ||
|
|
2fedabd3b9 | ||
|
|
6d719e9480 | ||
|
|
05e278afda | ||
|
|
87dbf462cb | ||
|
|
40e896bc5b | ||
|
|
3e940f80c7 | ||
|
|
dbf2888d43 | ||
|
|
d412355324 | ||
|
|
178732217f | ||
|
|
de17b95c3d | ||
|
|
d14e774525 | ||
|
|
ca5402a7fa | ||
|
|
7a6fa7c5b4 | ||
|
|
da36c286a6 | ||
|
|
d3901bcf2e | ||
|
|
94c8d4fdfb | ||
|
|
ab8bdc18bb | ||
|
|
c9dcd7442a | ||
|
|
34c8f13346 | ||
|
|
7a8ccda95c | ||
|
|
44a1448542 | ||
|
|
c87d89ffaf | ||
|
|
0868749d42 | ||
|
|
1d40ee23f0 | ||
|
|
8893f32603 | ||
|
|
adcf7e8dc3 | ||
|
|
901f7c5c36 | ||
|
|
775bb413b3 | ||
|
|
64cd5b5a46 | ||
|
|
ae356609b1 | ||
|
|
6102a5d2b0 | ||
|
|
f8782ee2d7 | ||
|
|
6181ec4c77 | ||
|
|
e0e7a685ef | ||
|
|
ae1f8cdad2 | ||
|
|
a4cf792e6d | ||
|
|
89109ded53 | ||
|
|
e20e52a4b2 | ||
|
|
20c4b1cbec | ||
|
|
5238b0241d | ||
|
|
9cdf6c203d | ||
|
|
839335cae6 | ||
|
|
a99b2ce167 | ||
|
|
b695141d87 | ||
|
|
92d5c9f866 | ||
|
|
7f18a1ffe0 | ||
|
|
8c3fdaaa62 | ||
|
|
5ac1c69710 | ||
|
|
de2d5fba63 | ||
|
|
33d516748f | ||
|
|
de17f6f0fd | ||
|
|
756731fc02 | ||
|
|
e46be0415f | ||
|
|
aa02fb50bf | ||
|
|
8b6cd9c772 | ||
|
|
cdd0d3351a | ||
|
|
8b6d584529 | ||
|
|
f49fdd4141 | ||
|
|
b26e1be81a | ||
|
|
bacab38d7f | ||
|
|
701c05ce96 | ||
|
|
438c452585 | ||
|
|
0a7a1eff3f | ||
|
|
87e743e381 | ||
|
|
a03f1b3d55 | ||
|
|
2d8dc3d243 | ||
|
|
b982232cc5 | ||
|
|
61c8d728ac | ||
|
|
851a2bf855 | ||
|
|
e0bdde3630 | ||
|
|
6a0dcd7f0e | ||
|
|
75f0b4c879 | ||
|
|
db536a9504 | ||
|
|
0fb114dede | ||
|
|
e703342179 | ||
|
|
35c8f4a611 | ||
|
|
7c89ae44a9 | ||
|
|
84fe06da22 | ||
|
|
806318c8b3 | ||
|
|
3aac2e1822 | ||
|
|
168baef433 | ||
|
|
6dba6cd78d | ||
|
|
502250d08f | ||
|
|
7395f0e680 | ||
|
|
494d3fdaca | ||
|
|
7b86a157de | ||
|
|
0988c41785 | ||
|
|
522db1bf01 | ||
|
|
06f066f90d | ||
|
|
f37b20677b | ||
|
|
cd2eac1032 | ||
|
|
8ac38d58d7 | ||
|
|
4c80cc313a | ||
|
|
1c65fee9b4 | ||
|
|
90dda7edc1 | ||
|
|
da054fae20 | ||
|
|
bdb6611e30 | ||
|
|
9284f973f1 | ||
|
|
2bfd64c3c9 | ||
|
|
939d24cce5 | ||
|
|
27b0183c46 | ||
|
|
d14efacac7 | ||
|
|
150a002c40 | ||
|
|
ce0def3bd8 | ||
|
|
ee20fa97c2 | ||
|
|
7403b7d700 | ||
|
|
87ef173e0a | ||
|
|
52a3fb6bc7 | ||
|
|
92e2a257a6 | ||
|
|
32e175752c | ||
|
|
d43f7180dc | ||
|
|
0129c2b0fc | ||
|
|
4ed1990001 | ||
|
|
5bd6ab27ae | ||
|
|
f3593b89fa | ||
|
|
23d84b2310 | ||
|
|
fdc49402ec | ||
|
|
5457c133e1 | ||
|
|
292e588ee3 | ||
|
|
243494c25e | ||
|
|
e4365f3706 | ||
|
|
310f3038d3 | ||
|
|
4e6033273d | ||
|
|
73718586d3 | ||
|
|
011abe61e8 |
141
WHATS_NEW
141
WHATS_NEW
@@ -1,5 +1,142 @@
|
||||
Version 2.01.00 -
|
||||
==================================
|
||||
Version 2.01.11 -
|
||||
==============================
|
||||
Remove hard-coded 64k text metadata writing restriction.
|
||||
Make VG name restrictions consistent.
|
||||
Introduce lvconvert. So far only removes mirror images.
|
||||
Allow mirror images to be resized.
|
||||
Allow mirror images to have more than one segment.
|
||||
Centralise restrictions on LV names.
|
||||
Always insert an intermediate layer for mirrors.
|
||||
Suppress hidden LVs from reports unless --all is given.
|
||||
Use square brackets for hidden LVs in reports.
|
||||
Allow the creation of mirrors with contiguous extents.
|
||||
Always perform sanity checks against metadata before committing it to disk.
|
||||
Split lv_extend into two steps: choosing extents + allocation to LV(s).
|
||||
Add mirror log region size to metadata.
|
||||
Use list_iterate_items throughout and add list*back macros.
|
||||
Introduce seg_ macros to access areas.
|
||||
Add segtype_is_ macros.
|
||||
Support tiny metadata areas for pool conversions.
|
||||
Mirror activation handles disk log as well as core.
|
||||
Activation code recognises mirror log dependency.
|
||||
Add mirror_log and regionsize fields to report.
|
||||
Fix non-orphan pvchange -u.
|
||||
Fix vgmerge to handle duplicate LVIDs.
|
||||
Move archiver code from tools into library.
|
||||
vgscan/change/display/vgs automatically create metadata backups if needed.
|
||||
Merge cloned allocation functions.
|
||||
Fix contiguous allocation policy with linear.
|
||||
Cope with missing format1 PVs again.
|
||||
Remove lists of free PV segments.
|
||||
Simplify pv_maps code and remove slow bitset algorithm.
|
||||
Red-Hat-ify the clvmd rhel4 initscript.
|
||||
%Zu->%zu
|
||||
Fix loopfiles alias alloc & mem debugging.
|
||||
Un-inline dbg_strdup.
|
||||
lv_reduce tidying.
|
||||
Remove some unnecessary parameters.
|
||||
Introduce seg_is macros.
|
||||
Don't defer closing dead FDs in clvmd.
|
||||
|
||||
Version 2.01.10 - 3rd May 2005
|
||||
==============================
|
||||
Don't create backup and archive dirs till needed.
|
||||
Reinstate full PV size when removing from VG.
|
||||
Support loopfiles for testing.
|
||||
Tidy lv_segment interface.
|
||||
pv_segment support.
|
||||
vgchange --physicalextentsize
|
||||
Internal snapshot restructuring.
|
||||
Remove unused internal non-persistent snapshot option.
|
||||
Allow offline extension of snapshot volumes.
|
||||
Move from 2-step to 3-step on-disk metadata commit.
|
||||
Scan ramdisks too and allow non-O_DIRECT fallback.
|
||||
Annotate, tidy and extend list.h.
|
||||
Alignment tidying.
|
||||
Make clvmd work around some "bugs" in gulm's node state notifications.
|
||||
Tidy clvmd's SIGHUP handler
|
||||
|
||||
Version 2.01.09 - 4th April 2005
|
||||
================================
|
||||
Add --ignorelockingfailure to vgmknodes.
|
||||
clvmd: Don't allow user operations to start until the lvm thread is fully up.
|
||||
clvmd-gulm: set KEEPALIVE on sockets.
|
||||
|
||||
Version 2.01.08 - 22nd March 2005
|
||||
=================================
|
||||
Add clustered attribute so vgchange can identify clustered VGs w/o locking.
|
||||
Improve detection of external changes affecting internal cache.
|
||||
Add 'already in device cache' debug message.
|
||||
Add -a to pvdisplay -C.
|
||||
Avoid rmdir opendir error messsages when dir was already removed.
|
||||
Tighten signal handlers.
|
||||
Avoid some compiler warnings.
|
||||
Additional rename failure error message.
|
||||
read/write may be macros.
|
||||
clvmd: don't take out lvm thread lock at startup, it only protects jobs list.
|
||||
|
||||
Version 2.01.07 - 8th March 2005
|
||||
================================
|
||||
Cope with new devices appearing by rescanning /dev if a uuid can't be found.
|
||||
Remove DESTDIR from LVM_SHARED_PATH.
|
||||
clvmd fixes: make FDs close-on-exec
|
||||
gulm unlocks VG & orphan locks at startup in case they are stale
|
||||
gulm now unlocks VG & orphan locks if client dies.
|
||||
|
||||
Version 2.01.06 - 1st March 2005
|
||||
================================
|
||||
Suppress 'open failed' error messages during scanning.
|
||||
Option to suppress warnings of file descriptors left open.
|
||||
Fix default value of metadatacopies in documentation (2->1).
|
||||
Fix clvmd-gulm locking.
|
||||
./configure --enable-debug now enables debugging code in clvmd.
|
||||
Fix clvmd-gulm node up/down code so it actually works.
|
||||
clvmd-gulm now releases locks when shut down.
|
||||
|
||||
Version 2.01.05 - 18th February 2005
|
||||
====================================
|
||||
Static binary invokes dynamic binary if appropriate.
|
||||
Make clvmd config check a little more tolerant.
|
||||
gulm clvmd can now cope with >1 message arriving in a TCP message.
|
||||
|
||||
Version 2.01.04 - 9th February 2005
|
||||
===================================
|
||||
Add fixed offset to imported pool minor numbers.
|
||||
Update binary pathnames in clvmd_init_rhel4.
|
||||
lvm2cmd.so should skip the check for open fds.
|
||||
Remove unused -f from pvmove.
|
||||
Gulm clvmd doesn't report "connection refused" errors.
|
||||
clvmd does a basic config file sanity check at startup.
|
||||
Fix potential thread shutdown race in clvmd.
|
||||
|
||||
Version 2.01.03 - 1st February 2005
|
||||
===================================
|
||||
More 64-bit display/report fixes.
|
||||
More informative startup mesg if can't create /etc/lvm.
|
||||
Fix snapshot device size bug (since 2.01.01).
|
||||
clvmd announces startup and cluster connection in syslog.
|
||||
Gulm clvmd doesn't hang trying to talk to a rebooted node.
|
||||
Gulm clvmd doesn't print cman error on startup.
|
||||
|
||||
Version 2.01.02 - 21st January 2005
|
||||
===================================
|
||||
Update clvmd_init_rhel4: use lvm.static and don't load dlm.
|
||||
Fix some size_t printing.
|
||||
Fix 64 bit xlate consts.
|
||||
Split out pool sptype_names to avoid unused const.
|
||||
Always fail if random id generation fails.
|
||||
Recognise gnbd devices.
|
||||
Fix clvmd startup bug introduced in cman/gulm amalgamation.
|
||||
Improve reporting of node-specific locking errors.
|
||||
|
||||
Version 2.01.01 - 19th January 2005
|
||||
===================================
|
||||
Fix clvmd lv_info_by_lvid open_count.
|
||||
Store snapshot and origin sizes separately.
|
||||
Update vgcreate man page.
|
||||
|
||||
Version 2.01.00 - 17th January 2005
|
||||
===================================
|
||||
Fix vgscan metadata auto-correction.
|
||||
Only ask libdevmapper for open_count when we need it.
|
||||
Adjust RHEL4 clvmd init script priority.
|
||||
|
||||
19
WHATS_NEW_DM
19
WHATS_NEW_DM
@@ -1,3 +1,22 @@
|
||||
Version 1.01.03 - 13 Jun 2005
|
||||
=============================
|
||||
Use matchpathcon mode parameter.
|
||||
Fix configure script to re-enable selinux.
|
||||
|
||||
Version 1.01.02 - 17 May 2005
|
||||
=============================
|
||||
Call dm_lib_exit() and dm_lib_release() automatically now.
|
||||
Add --target <target_type> filter to dmsetup table/status/ls.
|
||||
Add --exec <command> to dmsetup ls.
|
||||
Fix dmsetup getopt_long usage.
|
||||
|
||||
Version 1.01.01 - 29 Mar 2005
|
||||
=============================
|
||||
Update dmsetup man page.
|
||||
Drop-in devmap_name replacement.
|
||||
Add option to compile without ioctl for testing.
|
||||
Fix DM_LIB_VERSION sed.
|
||||
|
||||
Version 1.01.00 - 17 Jan 2005
|
||||
=============================
|
||||
Add dm_task_no_open_count() to skip getting open_count.
|
||||
|
||||
@@ -18,7 +18,6 @@ VPATH = @srcdir@
|
||||
SOURCES = \
|
||||
clvmd-command.c \
|
||||
clvmd.c \
|
||||
libclvm.c \
|
||||
lvm-functions.c \
|
||||
system-lv.c
|
||||
|
||||
@@ -35,6 +34,10 @@ ifeq ("@CLVMD@", "all")
|
||||
CMAN = yes
|
||||
endif
|
||||
|
||||
ifeq ("@DEBUG@", "yes")
|
||||
CFLAGS += -DDEBUG
|
||||
endif
|
||||
|
||||
ifeq ("$(GULM)", "yes")
|
||||
SOURCES += clvmd-gulm.c tcp-comms.c
|
||||
LMLIBS += -lccs -lgulm
|
||||
|
||||
@@ -43,6 +43,7 @@ struct clvm_header {
|
||||
/* Flags */
|
||||
#define CLVMD_FLAG_LOCAL 1 /* Only do this on the local node */
|
||||
#define CLVMD_FLAG_SYSTEMLV 2 /* Data in system LV under my node name */
|
||||
#define CLVMD_FLAG_NODEERRS 4 /* Reply has errors in node-specific portion */
|
||||
|
||||
/* Name of the local socket to communicate between libclvm and clvmd */
|
||||
//static const char CLVMD_SOCKNAME[]="/var/run/clvmd";
|
||||
|
||||
@@ -74,9 +74,11 @@ static int _init_cluster(void)
|
||||
/* Open the cluster communication socket */
|
||||
cluster_sock = socket(AF_CLUSTER, SOCK_DGRAM, CLPROTO_CLIENT);
|
||||
if (cluster_sock == -1) {
|
||||
syslog(LOG_ERR, "Can't open cman cluster manager socket: %m");
|
||||
/* Don't print an error here because we could be just probing for CMAN */
|
||||
return -1;
|
||||
}
|
||||
/* Set Close-on-exec */
|
||||
fcntl(cluster_sock, F_SETFD, 1);
|
||||
|
||||
/* Bind to our port number on the cluster.
|
||||
Writes to this will block if the cluster loses quorum */
|
||||
@@ -101,9 +103,15 @@ static int _init_cluster(void)
|
||||
return -1;
|
||||
}
|
||||
dlm_ls_pthread_init(lockspace);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_init_completed(void)
|
||||
{
|
||||
clvmd_cluster_init_completed();
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd()
|
||||
{
|
||||
return cluster_sock;
|
||||
@@ -507,7 +515,7 @@ static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_cman_ops = {
|
||||
.cluster_init_completed = NULL,
|
||||
.cluster_init_completed = _cluster_init_completed,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = _name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
|
||||
@@ -274,9 +274,10 @@ void cmd_client_cleanup(struct local_client *client)
|
||||
|
||||
hash_iterate(v, lock_hash) {
|
||||
int lkid = (int)(long)hash_get_data(lock_hash, v);
|
||||
char *lockname = hash_get_key(lock_hash, v);
|
||||
|
||||
DEBUGLOG("cleanup: Unlocking lkid %x\n", lkid);
|
||||
sync_unlock("DUMMY", lkid);
|
||||
DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid);
|
||||
sync_unlock(lockname, lkid);
|
||||
}
|
||||
|
||||
hash_destroy(lock_hash);
|
||||
|
||||
@@ -40,6 +40,7 @@ struct cluster_ops {
|
||||
|
||||
void (*get_our_csid) (char *csid);
|
||||
void (*add_up_node) (char *csid);
|
||||
void (*reread_config) (void);
|
||||
void (*cluster_closedown) (void);
|
||||
|
||||
int (*sync_lock) (const char *resource, int mode, int flags, int *lockid);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 2002-2003 All rights reserved.
|
||||
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
@@ -46,6 +47,7 @@
|
||||
#include "log.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "lvm-functions.h"
|
||||
#include "clvmd.h"
|
||||
#include "hash.h"
|
||||
#include "clvmd-gulm.h"
|
||||
@@ -58,13 +60,15 @@ static struct hash_table *node_hash;
|
||||
/* hash list of outstanding lock requests */
|
||||
static struct hash_table *lock_hash;
|
||||
|
||||
/* Copy of the current core state */
|
||||
static uint8_t current_corestate;
|
||||
/* Copy of the current quorate state */
|
||||
static uint8_t gulm_quorate = 0;
|
||||
static enum {INIT_NOTDONE, INIT_DONE, INIT_WAITQUORATE} init_state = INIT_NOTDONE;
|
||||
|
||||
/* Number of active nodes */
|
||||
static int num_nodes;
|
||||
|
||||
static char *cluster_name;
|
||||
static int in_shutdown = 0;
|
||||
|
||||
static pthread_mutex_t lock_start_mutex;
|
||||
static volatile int lock_start_flag;
|
||||
@@ -114,6 +118,9 @@ static int add_internal_client(int fd, fd_callback_t callback)
|
||||
client->callback = callback;
|
||||
add_client(client);
|
||||
|
||||
/* Set Close-on-exec */
|
||||
fcntl(fd, F_SETFD, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -129,12 +136,11 @@ static void badsig_handler(int sig)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void sighup_handler(int sig)
|
||||
static void _reread_config(void)
|
||||
{
|
||||
DEBUGLOG("got SIGHUP\n");
|
||||
|
||||
/* Re-read CCS node list */
|
||||
get_all_cluster_nodes();
|
||||
/* Re-read CCS node list */
|
||||
DEBUGLOG("Re-reading CCS config\n");
|
||||
get_all_cluster_nodes();
|
||||
}
|
||||
|
||||
static int _init_cluster(void)
|
||||
@@ -224,7 +230,7 @@ static int _init_cluster(void)
|
||||
exit(status);
|
||||
}
|
||||
|
||||
/* Request a list of nodes, we can;t really do anything until
|
||||
/* Request a list of nodes, we can't really do anything until
|
||||
this comes back */
|
||||
status = lg_core_nodelist(gulm_if);
|
||||
if (status)
|
||||
@@ -237,15 +243,14 @@ static int _init_cluster(void)
|
||||
signal(SIGINT, badsig_handler);
|
||||
signal(SIGTERM, badsig_handler);
|
||||
|
||||
/* Re-read the node list on SIGHUP */
|
||||
signal(SIGHUP, sighup_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
DEBUGLOG("cluster_closedown\n");
|
||||
in_shutdown = 1;
|
||||
unlock_all();
|
||||
lg_lock_logout(gulm_if);
|
||||
lg_core_logout(gulm_if);
|
||||
lg_release(gulm_if);
|
||||
@@ -258,6 +263,7 @@ static void drop_expired_locks(char *nodename)
|
||||
struct utsname nodeinfo;
|
||||
uint8_t mask[GIO_KEY_SIZE];
|
||||
|
||||
DEBUGLOG("Dropping expired locks for %s\n", nodename?nodename:"(null)");
|
||||
memset(mask, 0xff, GIO_KEY_SIZE);
|
||||
|
||||
if (!nodename)
|
||||
@@ -303,12 +309,16 @@ static int core_login_reply(void *misc, uint64_t gen, uint32_t error, uint32_t r
|
||||
if (error)
|
||||
exit(error);
|
||||
|
||||
current_corestate = corestate;
|
||||
/* Get the current core state (for quorum) */
|
||||
lg_core_corestate(gulm_if);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_node_state(struct node_info *ninfo, char *csid, uint8_t nodestate)
|
||||
{
|
||||
int oldstate = ninfo->state;
|
||||
|
||||
if (nodestate == lg_core_Logged_in)
|
||||
{
|
||||
/* Don't clobber NODE_CLVMD state */
|
||||
@@ -330,11 +340,17 @@ static void set_node_state(struct node_info *ninfo, char *csid, uint8_t nodestat
|
||||
if (ninfo->state != NODE_DOWN)
|
||||
num_nodes--;
|
||||
ninfo->state = NODE_DOWN;
|
||||
tcp_remove_client(csid);
|
||||
}
|
||||
}
|
||||
DEBUGLOG("set_node_state, '%s' state = %d, num_nodes=%d\n",
|
||||
ninfo->name, ninfo->state, num_nodes);
|
||||
/* Gulm doesn't always send node DOWN events, so even if this a a node UP we must
|
||||
* assume (ahem) that it prevously went down at some time. So we close
|
||||
* the sockets here to make sure that we don't have any dead connections
|
||||
* to that node.
|
||||
*/
|
||||
tcp_remove_client(csid);
|
||||
|
||||
DEBUGLOG("set_node_state, '%s' state = %d (oldstate=%d), num_nodes=%d\n",
|
||||
ninfo->name, ninfo->state, oldstate, num_nodes);
|
||||
}
|
||||
|
||||
static struct node_info *add_or_set_node(char *name, struct in6_addr *ip, uint8_t state)
|
||||
@@ -358,7 +374,7 @@ static struct node_info *add_or_set_node(char *name, struct in6_addr *ip, uint8_
|
||||
}
|
||||
}
|
||||
|
||||
set_node_state(ninfo, (char *)&ip, state);
|
||||
set_node_state(ninfo, (char *)ip, state);
|
||||
|
||||
return ninfo;
|
||||
}
|
||||
@@ -391,7 +407,16 @@ static int core_nodelist(void *misc, lglcb_t type, char *name, struct in6_addr *
|
||||
char ourcsid[GULM_MAX_CSID_LEN];
|
||||
|
||||
DEBUGLOG("Got Nodelist, stop\n");
|
||||
clvmd_cluster_init_completed();
|
||||
if (gulm_quorate)
|
||||
{
|
||||
clvmd_cluster_init_completed();
|
||||
init_state = INIT_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (init_state == INIT_NOTDONE)
|
||||
init_state = INIT_WAITQUORATE;
|
||||
}
|
||||
|
||||
/* Mark ourself as up */
|
||||
_get_our_csid(ourcsid);
|
||||
@@ -409,10 +434,15 @@ static int core_nodelist(void *misc, lglcb_t type, char *name, struct in6_addr *
|
||||
|
||||
static int core_statechange(void *misc, uint8_t corestate, uint8_t quorate, struct in6_addr *masterip, char *mastername)
|
||||
{
|
||||
DEBUGLOG("CORE Got statechange corestate:%#x mastername:%s\n",
|
||||
corestate, mastername);
|
||||
DEBUGLOG("CORE Got statechange. quorate:%d, corestate:%x mastername:%s\n",
|
||||
quorate, corestate, mastername);
|
||||
|
||||
current_corestate = corestate;
|
||||
gulm_quorate = quorate;
|
||||
if (quorate && init_state == INIT_WAITQUORATE)
|
||||
{
|
||||
clvmd_cluster_init_completed();
|
||||
init_state = INIT_DONE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -478,6 +508,10 @@ static int lock_lock_state(void *misc, uint8_t *key, uint16_t keylen,
|
||||
|
||||
DEBUGLOG("LOCK lock state: %s, error = %d\n", key, error);
|
||||
|
||||
/* No waiting process to wake up when we are shutting down */
|
||||
if (in_shutdown)
|
||||
return 0;
|
||||
|
||||
lwait = hash_lookup(lock_hash, key);
|
||||
if (!lwait)
|
||||
{
|
||||
@@ -596,10 +630,17 @@ void gulm_add_up_node(char *csid)
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
|
||||
if (!ninfo)
|
||||
if (!ninfo) {
|
||||
DEBUGLOG("gulm_add_up_node no node_hash entry for csid %s\n", print_csid(csid));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGLOG("gulm_add_up_node %s\n", ninfo->name);
|
||||
|
||||
if (ninfo->state == NODE_DOWN)
|
||||
num_nodes++;
|
||||
ninfo->state = NODE_CLVMD;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
@@ -616,13 +657,14 @@ void add_down_node(char *csid)
|
||||
running clvmd - gulm may set it DOWN quite soon */
|
||||
if (ninfo->state == NODE_CLVMD)
|
||||
ninfo->state = NODE_UP;
|
||||
drop_expired_locks(ninfo->name);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Call a callback for each node, so the caller knows whether it's up or down */
|
||||
static int _cluster_do_node_callback(struct local_client *master_client,
|
||||
void (*callback)(struct local_client *, char *csid, int node_up))
|
||||
void (*callback)(struct local_client *, char *csid, int node_up))
|
||||
{
|
||||
struct hash_node *hn;
|
||||
struct node_info *ninfo;
|
||||
@@ -638,8 +680,19 @@ static int _cluster_do_node_callback(struct local_client *master_client,
|
||||
DEBUGLOG("down_callback. node %s, state = %d\n", ninfo->name, ninfo->state);
|
||||
|
||||
client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
if (client)
|
||||
callback(master_client, csid, ninfo->state == NODE_CLVMD);
|
||||
if (!client)
|
||||
{
|
||||
/* If it's up but not connected, try to make contact */
|
||||
if (ninfo->state == NODE_UP)
|
||||
gulm_connect_csid(csid, &client);
|
||||
|
||||
client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
|
||||
}
|
||||
if (ninfo->state != NODE_DOWN)
|
||||
callback(master_client, csid, ninfo->state == NODE_CLVMD);
|
||||
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -650,15 +703,13 @@ static int gulm_to_errno(int gulm_ret)
|
||||
switch (gulm_ret)
|
||||
{
|
||||
case lg_err_TryFailed:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
|
||||
case lg_err_AlreadyPend:
|
||||
errno = EBUSY;
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
|
||||
/* More?? */
|
||||
default:
|
||||
errno = EINVAL;
|
||||
errno = EINVAL;
|
||||
}
|
||||
|
||||
return gulm_ret ? -1 : 0;
|
||||
@@ -729,6 +780,11 @@ static int _unlock_resource(char *resource, int lockid)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* When we are shutting down, don't wait for unlocks
|
||||
to be acknowledged, just do it. */
|
||||
if (in_shutdown)
|
||||
return status;
|
||||
|
||||
/* Wait for it to complete */
|
||||
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
@@ -765,7 +821,7 @@ static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
/* If we can't get this lock then bail out */
|
||||
/* If we can't get this lock too then bail out */
|
||||
status = _lock_resource(lock2, lg_lock_state_Exclusive, LCK_NONBLOCK, lockid);
|
||||
if (status == lg_err_TryFailed)
|
||||
{
|
||||
@@ -777,10 +833,16 @@ static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
|
||||
case LCK_READ:
|
||||
status = _lock_resource(lock1, lg_lock_state_Shared, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
status = _unlock_resource(lock2, *lockid);
|
||||
break;
|
||||
|
||||
case LCK_WRITE:
|
||||
status = _lock_resource(lock2, lg_lock_state_Exclusive, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
status = _unlock_resource(lock1, *lockid);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -807,36 +869,16 @@ static int _sync_unlock(const char *resource, int lockid)
|
||||
lockid == LCK_READ ||
|
||||
lockid == LCK_WRITE);
|
||||
|
||||
switch (lockid)
|
||||
{
|
||||
case LCK_EXCL:
|
||||
status = _unlock_resource(lock1, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
status = _unlock_resource(lock2, lockid);
|
||||
break;
|
||||
status = _unlock_resource(lock1, lockid);
|
||||
if (!status)
|
||||
status = _unlock_resource(lock2, lockid);
|
||||
|
||||
case LCK_READ:
|
||||
status = _unlock_resource(lock1, lockid);
|
||||
break;
|
||||
|
||||
case LCK_WRITE:
|
||||
status = _unlock_resource(lock2, lockid);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int _is_quorate()
|
||||
{
|
||||
if (current_corestate == lg_core_Slave ||
|
||||
current_corestate == lg_core_Master ||
|
||||
current_corestate == lg_core_Client)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
return gulm_quorate;
|
||||
}
|
||||
|
||||
/* Get all the cluster node names & IPs from CCS and
|
||||
@@ -913,11 +955,6 @@ static int get_all_cluster_nodes()
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_init_completed(void)
|
||||
{
|
||||
clvmd_cluster_init_completed();
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
return get_main_gulm_cluster_fd();
|
||||
@@ -934,7 +971,7 @@ static int _cluster_send_message(void *buf, int msglen, char *csid, const char *
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_gulm_ops = {
|
||||
.cluster_init_completed = _cluster_init_completed,
|
||||
.cluster_init_completed = NULL,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = gulm_name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
@@ -945,6 +982,7 @@ static struct cluster_ops _cluster_gulm_ops = {
|
||||
.is_quorate = _is_quorate,
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = gulm_add_up_node,
|
||||
.reread_config = _reread_config,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.sync_lock = _sync_lock,
|
||||
.sync_unlock = _sync_unlock,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "clvmd-comms.h"
|
||||
@@ -86,8 +87,10 @@ struct lvm_thread_cmd {
|
||||
static pthread_t lvm_thread;
|
||||
static pthread_mutex_t lvm_thread_mutex;
|
||||
static pthread_cond_t lvm_thread_cond;
|
||||
static pthread_mutex_t lvm_start_mutex;
|
||||
static struct list lvm_cmd_head;
|
||||
static int quit = 0;
|
||||
static volatile sig_atomic_t quit = 0;
|
||||
static volatile sig_atomic_t reread_config = 0;
|
||||
static int child_pipe[2];
|
||||
|
||||
/* Reasons the daemon failed initialisation */
|
||||
@@ -99,6 +102,7 @@ static int child_pipe[2];
|
||||
|
||||
/* Prototypes for code further down */
|
||||
static void sigusr2_handler(int sig);
|
||||
static void sighup_handler(int sig);
|
||||
static void sigterm_handler(int sig);
|
||||
static void send_local_reply(struct local_client *client, int status,
|
||||
int clientid);
|
||||
@@ -164,6 +168,7 @@ int main(int argc, char *argv[])
|
||||
int debug = 0;
|
||||
int cmd_timeout = DEFAULT_CMD_TIMEOUT;
|
||||
sigset_t ss;
|
||||
int using_gulm = 0;
|
||||
|
||||
/* Deal with command-line arguments */
|
||||
opterr = 0;
|
||||
@@ -219,8 +224,10 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* Set up signal handlers, USR1 is for cluster change notifications (in cman)
|
||||
USR2 causes child threads to exit.
|
||||
HUP causes gulm version to re-read nodes list from CCS.
|
||||
PIPE should be ignored */
|
||||
signal(SIGUSR2, sigusr2_handler);
|
||||
signal(SIGHUP, sighup_handler);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
/* Block SIGUSR2 in the main process */
|
||||
@@ -232,6 +239,7 @@ int main(int argc, char *argv[])
|
||||
list_init(&lvm_cmd_head);
|
||||
pthread_mutex_init(&lvm_thread_mutex, NULL);
|
||||
pthread_cond_init(&lvm_thread_cond, NULL);
|
||||
pthread_mutex_init(&lvm_start_mutex, NULL);
|
||||
init_lvhash();
|
||||
|
||||
/* Start the cluster interface */
|
||||
@@ -240,6 +248,7 @@ int main(int argc, char *argv[])
|
||||
max_csid_len = CMAN_MAX_CSID_LEN;
|
||||
max_cluster_message = CMAN_MAX_CLUSTER_MESSAGE;
|
||||
max_cluster_member_name_len = CMAN_MAX_CLUSTER_MEMBER_NAME_LEN;
|
||||
syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to CMAN");
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_GULM
|
||||
@@ -248,6 +257,8 @@ int main(int argc, char *argv[])
|
||||
max_csid_len = GULM_MAX_CSID_LEN;
|
||||
max_cluster_message = GULM_MAX_CLUSTER_MESSAGE;
|
||||
max_cluster_member_name_len = GULM_MAX_CLUSTER_MEMBER_NAME_LEN;
|
||||
using_gulm = 1;
|
||||
syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to GULM");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -273,6 +284,7 @@ int main(int argc, char *argv[])
|
||||
child_init_signal(DFAIL_MALLOC);
|
||||
|
||||
newfd->fd = local_sock;
|
||||
newfd->removeme = 0;
|
||||
newfd->type = LOCAL_RENDEZVOUS;
|
||||
newfd->callback = local_rendezvous_callback;
|
||||
newfd->next = local_client_head.next;
|
||||
@@ -281,7 +293,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, nodeinfo.nodename);
|
||||
pthread_create(&lvm_thread, NULL, lvm_thread_fn, (void *)using_gulm);
|
||||
|
||||
/* Tell the rest of the cluster our version number */
|
||||
/* CMAN can do this immediately, gulm needs to wait until
|
||||
@@ -339,6 +351,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
|
||||
newfd->fd = client_fd;
|
||||
newfd->type = LOCAL_SOCK;
|
||||
newfd->xid = 0;
|
||||
newfd->removeme = 0;
|
||||
newfd->callback = local_sock_callback;
|
||||
newfd->bits.localsock.replies = NULL;
|
||||
newfd->bits.localsock.expected_replies = 0;
|
||||
@@ -505,13 +518,38 @@ static void main_loop(int local_sock, int cmd_timeout)
|
||||
FD_SET(thisfd->fd, &in);
|
||||
}
|
||||
|
||||
if ((select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv)) > 0) {
|
||||
select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv);
|
||||
|
||||
if (reread_config) {
|
||||
int saved_errno = errno;
|
||||
|
||||
reread_config = 0;
|
||||
if (clops->reread_config)
|
||||
clops->reread_config();
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
if (select_status > 0) {
|
||||
struct local_client *lastfd = NULL;
|
||||
char csid[MAX_CSID_LEN];
|
||||
char buf[max_cluster_message];
|
||||
|
||||
for (thisfd = &local_client_head; thisfd != NULL;
|
||||
thisfd = thisfd->next) {
|
||||
|
||||
if (thisfd->removeme) {
|
||||
struct local_client *free_fd;
|
||||
lastfd->next = thisfd->next;
|
||||
free_fd = thisfd;
|
||||
thisfd = lastfd;
|
||||
|
||||
DEBUGLOG("removeme set for fd %d\n", free_fd->fd);
|
||||
|
||||
/* Queue cleanup, this also frees the client struct */
|
||||
add_to_lvmqueue(free_fd, NULL, 0, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(thisfd->fd, &in)) {
|
||||
struct local_client *newfd;
|
||||
int ret;
|
||||
@@ -540,8 +578,10 @@ static void main_loop(int local_sock, int cmd_timeout)
|
||||
lastfd->next = thisfd->next;
|
||||
free_fd = thisfd;
|
||||
thisfd = lastfd;
|
||||
cmd_client_cleanup(free_fd);
|
||||
free(free_fd);
|
||||
close(free_fd->fd);
|
||||
|
||||
/* Queue cleanup, this also frees the client struct */
|
||||
add_to_lvmqueue(free_fd, NULL, 0, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -716,7 +756,7 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
if (thisfd->bits.localsock.threadid) {
|
||||
DEBUGLOG("Waiting for child thread\n");
|
||||
pthread_mutex_lock(&thisfd->bits.localsock.mutex);
|
||||
thisfd->bits.localsock.state = POST_COMMAND;
|
||||
thisfd->bits.localsock.state = PRE_COMMAND;
|
||||
pthread_cond_signal(&thisfd->bits.localsock.cond);
|
||||
pthread_mutex_unlock(&thisfd->bits.localsock.mutex);
|
||||
pthread_kill(thisfd->bits.localsock.threadid, SIGUSR2);
|
||||
@@ -785,7 +825,7 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
if (thisfd->bits.localsock.in_progress) {
|
||||
struct clvm_header reply;
|
||||
reply.cmd = CLVMD_CMD_REPLY;
|
||||
reply.status = -EBUSY;
|
||||
reply.status = EBUSY;
|
||||
reply.arglen = 0;
|
||||
reply.flags = 0;
|
||||
send_message(&reply, sizeof(reply), our_csid,
|
||||
@@ -808,7 +848,7 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
if (!thisfd->bits.localsock.cmd) {
|
||||
struct clvm_header reply;
|
||||
reply.cmd = CLVMD_CMD_REPLY;
|
||||
reply.status = -ENOMEM;
|
||||
reply.status = ENOMEM;
|
||||
reply.arglen = 0;
|
||||
reply.flags = 0;
|
||||
send_message(&reply, sizeof(reply), our_csid,
|
||||
@@ -855,7 +895,7 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
DEBUGLOG("Unknown node: '%s'\n", inheader->node);
|
||||
|
||||
reply.cmd = CLVMD_CMD_REPLY;
|
||||
reply.status = -ENOENT;
|
||||
reply.status = ENOENT;
|
||||
reply.flags = 0;
|
||||
reply.arglen = 0;
|
||||
send_message(&reply, sizeof(reply), our_csid,
|
||||
@@ -886,7 +926,7 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
close(comms_pipe[1]);
|
||||
|
||||
reply.cmd = CLVMD_CMD_REPLY;
|
||||
reply.status = -ENOMEM;
|
||||
reply.status = ENOMEM;
|
||||
reply.arglen = 0;
|
||||
reply.flags = 0;
|
||||
send_message(&reply, sizeof(reply), our_csid,
|
||||
@@ -897,6 +937,7 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
DEBUGLOG("creating pipe, [%d, %d]\n", comms_pipe[0],
|
||||
comms_pipe[1]);
|
||||
newfd->fd = comms_pipe[0];
|
||||
newfd->removeme = 0;
|
||||
newfd->type = THREAD_PIPE;
|
||||
newfd->callback = local_pipe_callback;
|
||||
newfd->next = thisfd->next;
|
||||
@@ -1053,8 +1094,8 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
/* Get the node name as we /may/ need it later */
|
||||
clops->name_from_csid(csid, nodename);
|
||||
|
||||
DEBUGLOG("process_remote_command %d for clientid 0x%x on node %s\n",
|
||||
msg->cmd, msg->clientid, nodename);
|
||||
DEBUGLOG("process_remote_command %d for clientid 0x%x XID %d on node %s\n",
|
||||
msg->cmd, msg->clientid, msg->xid, nodename);
|
||||
|
||||
/* Is the data to be found in the system LV ? */
|
||||
if (msg->flags & CLVMD_FLAG_SYSTEMLV) {
|
||||
@@ -1076,7 +1117,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
|
||||
/* Return a failure response */
|
||||
head.cmd = CLVMD_CMD_REPLY;
|
||||
head.status = -EFBIG;
|
||||
head.status = EFBIG;
|
||||
head.flags = 0;
|
||||
head.clientid = msg->clientid;
|
||||
head.arglen = 0;
|
||||
@@ -1093,7 +1134,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
msg->arglen);
|
||||
/* Return a failure response */
|
||||
head.cmd = CLVMD_CMD_REPLY;
|
||||
head.status = -ENOMEM;
|
||||
head.status = ENOMEM;
|
||||
head.flags = 0;
|
||||
head.clientid = msg->clientid;
|
||||
head.arglen = 0;
|
||||
@@ -1156,7 +1197,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
do_command(NULL, msg, msglen, &replyargs, buflen,
|
||||
&replylen);
|
||||
} else {
|
||||
status = -ENOMEM;
|
||||
status = ENOMEM;
|
||||
}
|
||||
|
||||
/* If it wasn't a reply, then reply */
|
||||
@@ -1187,11 +1228,10 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
|
||||
/* If System LV operation failed then report it as EFBIG but only do it
|
||||
if the data buffer has something in it. */
|
||||
if (system_lv_write_data
|
||||
(aggreply,
|
||||
replylen + sizeof(struct clvm_header)) < 0
|
||||
if (system_lv_write_data(aggreply,
|
||||
replylen + sizeof(struct clvm_header)) < 0
|
||||
&& replylen > 0)
|
||||
agghead->status = -EFBIG;
|
||||
agghead->status = EFBIG;
|
||||
|
||||
send_message(agghead,
|
||||
sizeof(struct clvm_header), csid,
|
||||
@@ -1207,7 +1247,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
agghead->node[0] = '\0';
|
||||
send_message(aggreply,
|
||||
sizeof(struct clvm_header) +
|
||||
replylen + 2, csid, fd,
|
||||
replylen, csid, fd,
|
||||
"Error sending command reply");
|
||||
}
|
||||
} else {
|
||||
@@ -1216,7 +1256,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
DEBUGLOG("Error attempting to realloc return buffer\n");
|
||||
/* Return a failure response */
|
||||
head.cmd = CLVMD_CMD_REPLY;
|
||||
head.status = -ENOMEM;
|
||||
head.status = ENOMEM;
|
||||
head.flags = 0;
|
||||
head.clientid = msg->clientid;
|
||||
head.arglen = 0;
|
||||
@@ -1254,7 +1294,7 @@ static void add_reply_to_list(struct local_client *client, int status,
|
||||
if (len > 0) {
|
||||
reply->replymsg = malloc(len);
|
||||
if (!reply->replymsg) {
|
||||
reply->status = -ENOMEM;
|
||||
reply->status = ENOMEM;
|
||||
} else {
|
||||
memcpy(reply->replymsg, buf, len);
|
||||
}
|
||||
@@ -1298,6 +1338,11 @@ static void *pre_and_post_thread(void *arg)
|
||||
|
||||
DEBUGLOG("in sub thread: client = %p\n", client);
|
||||
|
||||
/* Don't start until the LVM thread is ready */
|
||||
pthread_mutex_lock(&lvm_start_mutex);
|
||||
pthread_mutex_unlock(&lvm_start_mutex);
|
||||
DEBUGLOG("Sub thread ready for work.\n");
|
||||
|
||||
/* Ignore SIGUSR1 (handled by master process) but enable
|
||||
SIGUSR2 (kills subthreads) */
|
||||
sigemptyset(&ss);
|
||||
@@ -1333,14 +1378,12 @@ static void *pre_and_post_thread(void *arg)
|
||||
|
||||
DEBUGLOG("Got post command condition...\n");
|
||||
|
||||
/* POST function must always run, even if the client aborts */
|
||||
status = 0;
|
||||
do_post_command(client);
|
||||
|
||||
write(pipe_fd, &status, sizeof(int));
|
||||
|
||||
if (client->bits.localsock.finished)
|
||||
break;
|
||||
|
||||
DEBUGLOG("Waiting for next pre command\n");
|
||||
|
||||
pthread_mutex_lock(&client->bits.localsock.mutex);
|
||||
@@ -1445,9 +1488,10 @@ static void send_local_reply(struct local_client *client, int status, int fd)
|
||||
replybuf = malloc(message_len);
|
||||
|
||||
clientreply = (struct clvm_header *) replybuf;
|
||||
clientreply->status = -status;
|
||||
clientreply->status = status;
|
||||
clientreply->cmd = CLVMD_CMD_REPLY;
|
||||
clientreply->node[0] = '\0';
|
||||
clientreply->flags = 0;
|
||||
|
||||
ptr = clientreply->args;
|
||||
|
||||
@@ -1459,6 +1503,9 @@ static void send_local_reply(struct local_client *client, int status, int fd)
|
||||
strcpy(ptr, thisreply->node);
|
||||
ptr += strlen(thisreply->node) + 1;
|
||||
|
||||
if (thisreply->status)
|
||||
clientreply->flags |= CLVMD_FLAG_NODEERRS;
|
||||
|
||||
*(int *) ptr = thisreply->status;
|
||||
ptr += sizeof(int);
|
||||
|
||||
@@ -1527,6 +1574,7 @@ static void send_version_message()
|
||||
version_nums[1] = htonl(CLVMD_MINOR_VERSION);
|
||||
version_nums[2] = htonl(CLVMD_PATCH_VERSION);
|
||||
|
||||
hton_clvm(msg);
|
||||
clops->cluster_send_message(message, sizeof(message), NULL,
|
||||
"Error Sending version number");
|
||||
}
|
||||
@@ -1539,7 +1587,7 @@ static int send_message(void *buf, int msglen, char *csid, int fd,
|
||||
|
||||
/* Send remote messages down the cluster socket */
|
||||
if (csid == NULL || !ISLOCAL_CSID(csid)) {
|
||||
hton_clvm((struct clvm_header *) buf); /* Byte swap if necessary */
|
||||
hton_clvm((struct clvm_header *) buf);
|
||||
return clops->cluster_send_message(buf, msglen, csid, errtext);
|
||||
} else {
|
||||
int ptr = 0;
|
||||
@@ -1560,6 +1608,14 @@ static int send_message(void *buf, int msglen, char *csid, int fd,
|
||||
|
||||
static int process_work_item(struct lvm_thread_cmd *cmd)
|
||||
{
|
||||
/* If msg is NULL then this is a cleanup request */
|
||||
if (cmd->msg == NULL) {
|
||||
DEBUGLOG("process_work_item: free fd %d\n", cmd->client->fd);
|
||||
cmd_client_cleanup(cmd->client);
|
||||
free(cmd->client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!cmd->remote) {
|
||||
DEBUGLOG("process_work_item: local\n");
|
||||
process_local_command(cmd->msg, cmd->msglen, cmd->client,
|
||||
@@ -1579,9 +1635,12 @@ static void *lvm_thread_fn(void *arg)
|
||||
{
|
||||
struct list *cmdl, *tmp;
|
||||
sigset_t ss;
|
||||
int using_gulm = (int)arg;
|
||||
|
||||
/* Don't let anyone else to do work until we are started */
|
||||
pthread_mutex_lock(&lvm_start_mutex);
|
||||
|
||||
DEBUGLOG("LVM thread function started\n");
|
||||
pthread_mutex_lock(&lvm_thread_mutex);
|
||||
|
||||
/* Ignore SIGUSR1 & 2 */
|
||||
sigemptyset(&ss);
|
||||
@@ -1590,8 +1649,10 @@ static void *lvm_thread_fn(void *arg)
|
||||
pthread_sigmask(SIG_BLOCK, &ss, NULL);
|
||||
|
||||
/* Initialise the interface to liblvm */
|
||||
init_lvm();
|
||||
pthread_mutex_unlock(&lvm_thread_mutex);
|
||||
init_lvm(using_gulm);
|
||||
|
||||
/* Allow others to get moving */
|
||||
pthread_mutex_unlock(&lvm_start_mutex);
|
||||
|
||||
/* Now wait for some actual work */
|
||||
for (;;) {
|
||||
@@ -1610,7 +1671,8 @@ static void *lvm_thread_fn(void *arg)
|
||||
pthread_mutex_unlock(&lvm_thread_mutex);
|
||||
|
||||
process_work_item(cmd);
|
||||
free(cmd->msg);
|
||||
if (cmd->msg)
|
||||
free(cmd->msg);
|
||||
free(cmd);
|
||||
|
||||
pthread_mutex_lock(&lvm_thread_mutex);
|
||||
@@ -1627,19 +1689,24 @@ static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
|
||||
|
||||
cmd = malloc(sizeof(struct lvm_thread_cmd));
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
return ENOMEM;
|
||||
|
||||
cmd->msg = malloc(msglen);
|
||||
if (!cmd->msg) {
|
||||
log_error("Unable to allocate buffer space\n");
|
||||
free(cmd);
|
||||
return -1;
|
||||
if (msglen) {
|
||||
cmd->msg = malloc(msglen);
|
||||
if (!cmd->msg) {
|
||||
log_error("Unable to allocate buffer space\n");
|
||||
free(cmd);
|
||||
return -1;
|
||||
}
|
||||
memcpy(cmd->msg, msg, msglen);
|
||||
}
|
||||
else {
|
||||
cmd->msg = NULL;
|
||||
}
|
||||
|
||||
cmd->client = client;
|
||||
cmd->msglen = msglen;
|
||||
cmd->xid = client->xid;
|
||||
memcpy(cmd->msg, msg, msglen);
|
||||
|
||||
if (csid) {
|
||||
memcpy(cmd->csid, csid, max_csid_len);
|
||||
cmd->remote = 1;
|
||||
@@ -1672,6 +1739,8 @@ static int open_local_sock()
|
||||
log_error("Can't create local socket: %m");
|
||||
return -1;
|
||||
}
|
||||
/* Set Close-on-exec */
|
||||
fcntl(local_socket, F_SETFD, 1);
|
||||
|
||||
memset(&sockaddr, 0, sizeof(sockaddr));
|
||||
memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
|
||||
@@ -1709,7 +1778,7 @@ static void check_all_callback(struct local_client *client, char *csid,
|
||||
int node_up)
|
||||
{
|
||||
if (!node_up)
|
||||
add_reply_to_list(client, -EHOSTDOWN, csid, "CLVMD not running",
|
||||
add_reply_to_list(client, EHOSTDOWN, csid, "CLVMD not running",
|
||||
18);
|
||||
}
|
||||
|
||||
@@ -1766,6 +1835,12 @@ static void sigterm_handler(int sig)
|
||||
return;
|
||||
}
|
||||
|
||||
static void sighup_handler(int sig)
|
||||
{
|
||||
DEBUGLOG("got SIGHUP\n");
|
||||
reread_config = 1;
|
||||
}
|
||||
|
||||
int sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
return clops->sync_lock(resource, mode, flags, lockid);
|
||||
|
||||
@@ -86,6 +86,7 @@ struct local_client {
|
||||
struct local_client *next;
|
||||
unsigned short xid;
|
||||
fd_callback_t callback;
|
||||
uint8_t removeme;
|
||||
|
||||
union {
|
||||
struct localsock_bits localsock;
|
||||
@@ -93,9 +94,9 @@ struct local_client {
|
||||
struct netsock_bits net;
|
||||
} bits;
|
||||
};
|
||||
#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUGLOG(fmt, args...) fprintf(stderr, "CLVMD[%d]: %ld ", getpid(), time(NULL) ); fprintf(stderr, fmt, ## args)
|
||||
#define DEBUGLOG(fmt, args...) {time_t P; time(&P); fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 ); fprintf(stderr, fmt, ## args);}
|
||||
#else
|
||||
#define DEBUGLOG(fmt, args...)
|
||||
#endif
|
||||
|
||||
@@ -1,446 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1997-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
|
||||
*/
|
||||
|
||||
/* library functions for Cluster LVM Daemon */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <search.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "clvm.h"
|
||||
#include "libclvm.h"
|
||||
|
||||
/* CLVM in hex! */
|
||||
#define LVM_SIGNATURE 0x434C564D
|
||||
|
||||
#define MAX_CLUSTER_MEMBER_NAME_LEN 255
|
||||
|
||||
/* NOTE: the LVMD uses the socket FD as the client ID, this means
|
||||
that any client that calls fork() will inherit the context of
|
||||
it's parent. */
|
||||
static int clvmd_sock = -1;
|
||||
|
||||
static int open_local_sock(void)
|
||||
{
|
||||
int local_socket;
|
||||
struct sockaddr_un sockaddr;
|
||||
|
||||
/* Open local socket */
|
||||
local_socket = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (local_socket < 0) {
|
||||
perror("Can't create local socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fcntl(local_socket, F_SETFD, !FD_CLOEXEC);
|
||||
|
||||
strcpy(sockaddr.sun_path, CLVMD_SOCKNAME);
|
||||
sockaddr.sun_family = AF_UNIX;
|
||||
if (connect
|
||||
(local_socket, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) {
|
||||
int saved_errno = errno;
|
||||
|
||||
close(local_socket);
|
||||
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
return local_socket;
|
||||
}
|
||||
|
||||
/* Send a request and return the status */
|
||||
static int send_request(char *inbuf, int inlen, char **retbuf)
|
||||
{
|
||||
char outbuf[PIPE_BUF];
|
||||
struct clvm_header *outheader = (struct clvm_header *) outbuf;
|
||||
int len;
|
||||
int off;
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(clvmd_sock, &fds);
|
||||
|
||||
/* Send it to CLVMD */
|
||||
if (write(clvmd_sock, inbuf, inlen) != inlen) {
|
||||
perror("Error writing to CLVMD");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the response */
|
||||
if ((len = read(clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
|
||||
perror("Error reading CLVMD");
|
||||
return -1;
|
||||
}
|
||||
if (len == 0) {
|
||||
fprintf(stderr, "EOF reading CLVMD");
|
||||
errno = ENOTCONN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate buffer */
|
||||
*retbuf = malloc(len + outheader->arglen);
|
||||
if (!*retbuf) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy the header */
|
||||
memcpy(*retbuf, outbuf, len);
|
||||
outheader = (struct clvm_header *) *retbuf;
|
||||
|
||||
/* Read the returned values */
|
||||
off = 1; /* we've already read the first byte */
|
||||
|
||||
while (off < outheader->arglen && len > 0) {
|
||||
len = read(clvmd_sock, outheader->args + off, PIPE_BUF);
|
||||
if (len > 0)
|
||||
off += len;
|
||||
}
|
||||
|
||||
/* Was it an error ? */
|
||||
if (outheader->status < 0) {
|
||||
errno = -outheader->status;
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Build the structure header and parse-out wildcard node names */
|
||||
static void build_header(struct clvm_header *head, int cmd, const char *node,
|
||||
void *data, int len)
|
||||
{
|
||||
head->cmd = cmd;
|
||||
head->status = 0;
|
||||
head->flags = 0;
|
||||
head->clientid = 0;
|
||||
head->arglen = len;
|
||||
if (node) {
|
||||
/* Allow a couple of special node names:
|
||||
"*" for all nodes,
|
||||
"." for the local node only
|
||||
*/
|
||||
if (strcmp(node, "*") == 0) {
|
||||
head->node[0] = '\0';
|
||||
} else if (strcmp(node, ".") == 0) {
|
||||
head->node[0] = '\0';
|
||||
head->flags = CLVMD_FLAG_LOCAL;
|
||||
} else {
|
||||
strcpy(head->node, node);
|
||||
}
|
||||
} else {
|
||||
head->node[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Send a message to a(or all) node(s) in the cluster */
|
||||
int lvm_cluster_write(char cmd, char *node, void *data, int len)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
struct clvm_header *head = (struct clvm_header *) outbuf;
|
||||
|
||||
if (clvmd_sock == -1)
|
||||
clvmd_sock = open_local_sock();
|
||||
if (clvmd_sock == -1)
|
||||
return -1;
|
||||
|
||||
build_header(head, cmd, node, data, len);
|
||||
memcpy(head->node + strlen(head->node) + 1, data, len);
|
||||
|
||||
status =
|
||||
send_request(outbuf,
|
||||
sizeof(struct clvm_header) + strlen(head->node) + len,
|
||||
&retbuf);
|
||||
if (retbuf)
|
||||
free(retbuf);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* API: Send a message to a(or all) node(s) in the cluster
|
||||
and wait for replies */
|
||||
int lvm_cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
int *outptr;
|
||||
char *inptr;
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
int i;
|
||||
int num_responses = 0;
|
||||
struct clvm_header *head = (struct clvm_header *) outbuf;
|
||||
lvm_response_t *rarray;
|
||||
|
||||
*num = 0;
|
||||
|
||||
if (clvmd_sock == -1)
|
||||
clvmd_sock = open_local_sock();
|
||||
if (clvmd_sock == -1)
|
||||
return -1;
|
||||
|
||||
build_header(head, cmd, node, data, len);
|
||||
memcpy(head->node + strlen(head->node) + 1, data, len);
|
||||
|
||||
status =
|
||||
send_request(outbuf,
|
||||
sizeof(struct clvm_header) + strlen(head->node) + len,
|
||||
&retbuf);
|
||||
if (status == 0 || status == -2) {
|
||||
/* Count the number of responses we got */
|
||||
head = (struct clvm_header *) retbuf;
|
||||
inptr = head->args;
|
||||
while (inptr[0]) {
|
||||
num_responses++;
|
||||
inptr += strlen(inptr) + 1;
|
||||
inptr += sizeof(int);
|
||||
inptr += strlen(inptr) + 1;
|
||||
}
|
||||
|
||||
/* Allocate response array. With an extra pair of INTs on the front to sanity
|
||||
check the pointer when we are given it back to free */
|
||||
outptr =
|
||||
malloc(sizeof(lvm_response_t) * num_responses +
|
||||
sizeof(int) * 2);
|
||||
if (!outptr) {
|
||||
if (retbuf)
|
||||
free(retbuf);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*response = (lvm_response_t *) (outptr + 2);
|
||||
outptr[0] = LVM_SIGNATURE;
|
||||
outptr[1] = num_responses;
|
||||
rarray = *response;
|
||||
|
||||
/* Unpack the response into an lvm_response_t array */
|
||||
inptr = head->args;
|
||||
i = 0;
|
||||
while (inptr[0]) {
|
||||
strcpy(rarray[i].node, inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
|
||||
rarray[i].status = *(int *) inptr;
|
||||
inptr += sizeof(int);
|
||||
|
||||
rarray[i].response = malloc(strlen(inptr) + 1);
|
||||
if (rarray[i].response == NULL) {
|
||||
/* Free up everything else and return error */
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
free(rarray[i].response);
|
||||
free(outptr);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(rarray[i].response, inptr);
|
||||
rarray[i].len = strlen(inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
i++;
|
||||
}
|
||||
*num = num_responses;
|
||||
*response = rarray;
|
||||
}
|
||||
|
||||
if (retbuf)
|
||||
free(retbuf);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* API: Free reply array */
|
||||
int lvm_cluster_free_request(lvm_response_t * response)
|
||||
{
|
||||
int *ptr = (int *) response - 2;
|
||||
int i;
|
||||
int num;
|
||||
|
||||
/* Check it's ours to free */
|
||||
if (response == NULL || *ptr != LVM_SIGNATURE) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
num = ptr[1];
|
||||
for (i = 0; i < num; i++) {
|
||||
free(response[i].response);
|
||||
}
|
||||
free(ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* These are a "higher-level" API providing black-box lock/unlock
|
||||
functions for cluster LVM...maybe */
|
||||
|
||||
/* Set by lock(), used by unlock() */
|
||||
static int num_responses;
|
||||
static lvm_response_t *response;
|
||||
|
||||
int lvm_lock_for_cluster(char scope, char *name, int verbosity)
|
||||
{
|
||||
int status;
|
||||
int i;
|
||||
char *args;
|
||||
int len;
|
||||
|
||||
if (name) {
|
||||
len = strlen(name) + 2;
|
||||
args = alloca(len);
|
||||
strcpy(args + 1, name);
|
||||
} else {
|
||||
len = 2;
|
||||
args = alloca(len);
|
||||
args[1] = '\0';
|
||||
}
|
||||
args[0] = scope;
|
||||
|
||||
status = lvm_cluster_request(CLVMD_CMD_LOCK,
|
||||
"", args, len, &response, &num_responses);
|
||||
|
||||
/* If any nodes were down then display them and return an error */
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status == -EHOSTDOWN) {
|
||||
if (verbosity)
|
||||
fprintf(stderr,
|
||||
"clvmd not running on node %s\n",
|
||||
response[i].node);
|
||||
status = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there was an error then free the memory now as the caller won't
|
||||
want to do the unlock */
|
||||
if (status) {
|
||||
int saved_errno = errno;
|
||||
lvm_cluster_free_request(response);
|
||||
num_responses = 0;
|
||||
errno = saved_errno;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int lvm_unlock_for_cluster(char scope, char *name, int verbosity)
|
||||
{
|
||||
int status;
|
||||
int i;
|
||||
int len;
|
||||
int failed;
|
||||
int num_unlock_responses;
|
||||
char *args;
|
||||
lvm_response_t *unlock_response;
|
||||
|
||||
/* We failed - this should not have been called */
|
||||
if (num_responses == 0)
|
||||
return 0;
|
||||
|
||||
if (name) {
|
||||
len = strlen(name) + 2;
|
||||
args = alloca(len);
|
||||
strcpy(args + 1, name);
|
||||
} else {
|
||||
len = 2;
|
||||
args = alloca(len);
|
||||
args[1] = '\0';
|
||||
}
|
||||
args[0] = scope;
|
||||
|
||||
/* See if it failed anywhere */
|
||||
failed = 0;
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status != 0)
|
||||
failed++;
|
||||
}
|
||||
|
||||
/* If it failed on any nodes then we only unlock on
|
||||
the nodes that succeeded */
|
||||
if (failed) {
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
/* Unlock the ones that succeeded */
|
||||
if (response[i].status == 0) {
|
||||
status = lvm_cluster_request(CLVMD_CMD_UNLOCK,
|
||||
response[i].node,
|
||||
args, len,
|
||||
&unlock_response,
|
||||
&num_unlock_responses);
|
||||
if (status) {
|
||||
if (verbosity)
|
||||
fprintf(stderr,
|
||||
"cluster command to node %s failed: %s\n",
|
||||
response[i].node,
|
||||
strerror(errno));
|
||||
} else if (unlock_response[0].status != 0) {
|
||||
if (verbosity > 1)
|
||||
fprintf(stderr,
|
||||
"unlock on node %s failed: %s\n",
|
||||
response[i].node,
|
||||
strerror(unlock_response
|
||||
[0].status));
|
||||
}
|
||||
lvm_cluster_free_request(unlock_response);
|
||||
} else {
|
||||
if (verbosity)
|
||||
fprintf(stderr,
|
||||
"command on node %s failed: '%s' - will be left locked\n",
|
||||
response[i].node,
|
||||
strerror(response[i].status));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* All OK, we can do a full cluster unlock */
|
||||
status = lvm_cluster_request(CLVMD_CMD_UNLOCK,
|
||||
"",
|
||||
args, len,
|
||||
&unlock_response,
|
||||
&num_unlock_responses);
|
||||
if (status) {
|
||||
if (verbosity > 1)
|
||||
fprintf(stderr, "cluster command failed: %s\n",
|
||||
strerror(errno));
|
||||
} else {
|
||||
for (i = 0; i < num_unlock_responses; i++) {
|
||||
if (unlock_response[i].status != 0) {
|
||||
if (verbosity > 1)
|
||||
fprintf(stderr,
|
||||
"unlock on node %s failed: %s\n",
|
||||
response[i].node,
|
||||
strerror(unlock_response
|
||||
[0].status));
|
||||
}
|
||||
}
|
||||
}
|
||||
lvm_cluster_free_request(unlock_response);
|
||||
}
|
||||
lvm_cluster_free_request(response);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1997-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 _LIBCLVM_H
|
||||
#define _LIBCLVM_H
|
||||
|
||||
typedef struct lvm_response {
|
||||
char node[255];
|
||||
char *response;
|
||||
int status;
|
||||
int len;
|
||||
|
||||
} lvm_response_t;
|
||||
|
||||
extern int lvm_cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num);
|
||||
extern int lvm_cluster_write(char cmd, char *node, void *data, int len);
|
||||
extern int lvm_cluster_free_request(lvm_response_t * response);
|
||||
|
||||
/* The "high-level" API */
|
||||
extern int lvm_lock_for_cluster(char scope, char *name, int verbosity);
|
||||
extern int lvm_unlock_for_cluster(char scope, char *name, int verbosity);
|
||||
|
||||
#endif
|
||||
@@ -198,7 +198,7 @@ static int do_activate_lv(char *resource, int mode)
|
||||
return errno;
|
||||
|
||||
/* If it's suspended then resume it */
|
||||
if (!lv_info_by_lvid(cmd, resource, &lvi))
|
||||
if (!lv_info_by_lvid(cmd, resource, &lvi, 0))
|
||||
return EIO;
|
||||
|
||||
if (lvi.suspended)
|
||||
@@ -244,7 +244,7 @@ static int do_suspend_lv(char *resource)
|
||||
}
|
||||
|
||||
/* Only suspend it if it exists */
|
||||
if (!lv_info_by_lvid(cmd, resource, &lvi))
|
||||
if (!lv_info_by_lvid(cmd, resource, &lvi, 0))
|
||||
return EIO;
|
||||
|
||||
if (lvi.exists) {
|
||||
@@ -363,7 +363,7 @@ 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))
|
||||
if (!lv_info_by_lvid(cmd, resource, &lvi, 0))
|
||||
return EIO;
|
||||
|
||||
if (lvi.exists) {
|
||||
@@ -388,6 +388,44 @@ int do_check_lvm1(char *vgname)
|
||||
return status == 1 ? 0 : EBUSY;
|
||||
}
|
||||
|
||||
|
||||
/* Only called at gulm startup. Drop any leftover VG or P_orphan locks
|
||||
that might be hanging around if we died for any reason
|
||||
*/
|
||||
static void drop_vg_locks()
|
||||
{
|
||||
char vg[128];
|
||||
char line[255];
|
||||
FILE *vgs =
|
||||
popen
|
||||
("lvm pvs --nolocking --noheadings -o vg_name", "r");
|
||||
|
||||
sync_unlock("P_orphans", LCK_EXCL);
|
||||
|
||||
if (!vgs)
|
||||
return;
|
||||
|
||||
while (fgets(line, sizeof(line), vgs)) {
|
||||
char *vgend;
|
||||
char *vgstart;
|
||||
|
||||
if (line[strlen(line)-1] == '\n')
|
||||
line[strlen(line)-1] = '\0';
|
||||
|
||||
vgstart = line + strspn(line, " ");
|
||||
vgend = vgstart + strcspn(vgstart, " ");
|
||||
*vgend = '\0';
|
||||
|
||||
if (strncmp(vgstart, "WARNING:", 8) == 0)
|
||||
continue;
|
||||
|
||||
sprintf(vg, "V_%s", vgstart);
|
||||
sync_unlock(vg, LCK_EXCL);
|
||||
|
||||
}
|
||||
fclose(vgs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ideally, clvmd should be started before any LVs are active
|
||||
* but this may not be the case...
|
||||
@@ -400,7 +438,7 @@ static void *get_initial_state()
|
||||
char line[255];
|
||||
FILE *lvs =
|
||||
popen
|
||||
("/sbin/lvm lvs --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr",
|
||||
("lvm lvs --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr",
|
||||
"r");
|
||||
|
||||
if (!lvs)
|
||||
@@ -438,6 +476,30 @@ static void *get_initial_state()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This checks some basic cluster-LVM configuration stuff */
|
||||
static void check_config()
|
||||
{
|
||||
int locking_type;
|
||||
|
||||
locking_type = find_config_int(cmd->cft->root, "global/locking_type", 1);
|
||||
|
||||
if (locking_type == 3) /* compiled-in cluster support */
|
||||
return;
|
||||
|
||||
if (locking_type == 2) { /* External library, check name */
|
||||
const char *libname;
|
||||
|
||||
libname = find_config_str(cmd->cft->root, "global/locking_library",
|
||||
"");
|
||||
if (strstr(libname, "liblvm2clusterlock.so"))
|
||||
return;
|
||||
|
||||
log_error("Incorrect LVM locking library specified in lvm.conf, cluster operations may not work.");
|
||||
return;
|
||||
}
|
||||
log_error("locking_type not set correctly in lvm.conf, cluster operations will not work.");
|
||||
}
|
||||
|
||||
void init_lvhash()
|
||||
{
|
||||
/* Create hash table for keeping LV locks & status */
|
||||
@@ -446,7 +508,7 @@ void init_lvhash()
|
||||
}
|
||||
|
||||
/* Called to initialise the LVM context of the daemon */
|
||||
int init_lvm(void)
|
||||
int init_lvm(int using_gulm)
|
||||
{
|
||||
if (!(cmd = create_toolcontext(NULL))) {
|
||||
log_error("Failed to allocate command context");
|
||||
@@ -457,6 +519,13 @@ int init_lvm(void)
|
||||
init_syslog(LOG_DAEMON);
|
||||
init_debug(_LOG_ERR);
|
||||
|
||||
/* Check lvm.conf is setup for cluster-LVM */
|
||||
check_config();
|
||||
|
||||
/* Remove any non-LV locks that may have been left around */
|
||||
if (using_gulm)
|
||||
drop_vg_locks();
|
||||
|
||||
get_initial_state();
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -25,7 +25,7 @@ extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern int do_check_lvm1(char *vgname);
|
||||
extern int init_lvm(void);
|
||||
extern int init_lvm(int using_gulm);
|
||||
extern void init_lvhash(void);
|
||||
|
||||
extern int hold_unlock(char *resource);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 2002-2003 All rights reserved.
|
||||
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
@@ -68,6 +69,7 @@ int init_comms(unsigned short port)
|
||||
{
|
||||
int one = 1;
|
||||
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
|
||||
setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int));
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr)); // Bind to INADDR_ANY
|
||||
@@ -84,6 +86,9 @@ int init_comms(unsigned short port)
|
||||
|
||||
listen(listen_fd, 5);
|
||||
|
||||
/* Set Close-on-exec */
|
||||
fcntl(listen_fd, F_SETFD, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -100,6 +105,8 @@ void tcp_remove_client(char *csid)
|
||||
if (client)
|
||||
{
|
||||
hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
client->removeme = 1;
|
||||
close(client->fd);
|
||||
}
|
||||
|
||||
/* Look for a mangled one too */
|
||||
@@ -109,6 +116,8 @@ void tcp_remove_client(char *csid)
|
||||
if (client)
|
||||
{
|
||||
hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
client->removeme = 1;
|
||||
close(client->fd);
|
||||
}
|
||||
|
||||
/* Put it back as we found it */
|
||||
@@ -221,13 +230,34 @@ int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, char *
|
||||
return newfd;
|
||||
}
|
||||
|
||||
/* Try to get at least 'len' bytes from the socket */
|
||||
static int really_read(int fd, char *buf, int len)
|
||||
{
|
||||
int got, offset;
|
||||
|
||||
got = offset = 0;
|
||||
|
||||
do {
|
||||
got = read(fd, buf+offset, len-offset);
|
||||
DEBUGLOG("really_read. got %d bytes\n", got);
|
||||
offset += got;
|
||||
} while (got > 0 && offset < len);
|
||||
|
||||
if (got < 0)
|
||||
return got;
|
||||
else
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
static int read_from_tcpsock(struct local_client *client, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
struct sockaddr_in6 addr;
|
||||
socklen_t slen = sizeof(addr);
|
||||
struct clvm_header *header = (struct clvm_header *)buf;
|
||||
int status;
|
||||
uint32_t arglen;
|
||||
|
||||
DEBUGLOG("read_from_tcpsock fd %d\n", client->fd);
|
||||
*new_client = NULL;
|
||||
@@ -236,7 +266,26 @@ static int read_from_tcpsock(struct local_client *client, char *buf, int len, ch
|
||||
getpeername(client->fd, (struct sockaddr *)&addr, &slen);
|
||||
memcpy(csid, &addr.sin6_addr, GULM_MAX_CSID_LEN);
|
||||
|
||||
status = read(client->fd, buf, len);
|
||||
/* Read just the header first, then get the rest if there is any.
|
||||
* Stream sockets, sigh.
|
||||
*/
|
||||
status = really_read(client->fd, buf, sizeof(struct clvm_header));
|
||||
if (status > 0)
|
||||
{
|
||||
int status2;
|
||||
|
||||
arglen = ntohl(header->arglen);
|
||||
|
||||
/* Get the rest */
|
||||
if (arglen && arglen < GULM_MAX_CLUSTER_MESSAGE)
|
||||
{
|
||||
status2 = really_read(client->fd, buf+status, arglen);
|
||||
if (status2 > 0)
|
||||
status += status2;
|
||||
else
|
||||
status = status2;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGLOG("read_from_tcpsock, status = %d(errno = %d)\n", status, errno);
|
||||
|
||||
@@ -259,17 +308,19 @@ static int read_from_tcpsock(struct local_client *client, char *buf, int len, ch
|
||||
add_down_node(remcsid);
|
||||
}
|
||||
else {
|
||||
gulm_add_up_node(csid);
|
||||
/* Send it back to clvmd */
|
||||
process_message(client, buf, len, csid);
|
||||
process_message(client, buf, status, csid);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int connect_csid(char *csid, struct local_client **newclient)
|
||||
int gulm_connect_csid(char *csid, struct local_client **newclient)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in6 addr;
|
||||
int status;
|
||||
int one = 1;
|
||||
|
||||
DEBUGLOG("Connecting socket\n");
|
||||
fd = socket(PF_INET6, SOCK_STREAM, 0);
|
||||
@@ -287,12 +338,22 @@ static int connect_csid(char *csid, struct local_client **newclient)
|
||||
DEBUGLOG("Connecting socket %d\n", fd);
|
||||
if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Unable to connect to remote node: %m");
|
||||
/* "Connection refused" is "normal" because clvmd may not yet be running
|
||||
* on that node.
|
||||
*/
|
||||
if (errno != ECONNREFUSED)
|
||||
{
|
||||
syslog(LOG_ERR, "Unable to connect to remote node: %m");
|
||||
}
|
||||
DEBUGLOG("Unable to connect to remote node: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set Close-on-exec */
|
||||
fcntl(fd, F_SETFD, 1);
|
||||
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int));
|
||||
|
||||
status = alloc_client(fd, csid, newclient);
|
||||
if (status)
|
||||
close(fd);
|
||||
@@ -323,7 +384,7 @@ static int tcp_send_message(void *buf, int msglen, unsigned char *csid, const ch
|
||||
client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
if (!client)
|
||||
{
|
||||
status = connect_csid(csid, &client);
|
||||
status = gulm_connect_csid(csid, &client);
|
||||
if (status)
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -10,3 +10,4 @@ int get_main_gulm_cluster_fd(void);
|
||||
int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, char *csid, struct local_client **new_client);
|
||||
int gulm_cluster_send_message(void *buf, int msglen, char *csid, const char *errtext);
|
||||
void get_our_gulm_csid(char *csid);
|
||||
int gulm_connect_csid(char *csid, struct local_client **newclient);
|
||||
|
||||
3
daemons/dmeventd/.exported_symbols
Normal file
3
daemons/dmeventd/.exported_symbols
Normal file
@@ -0,0 +1,3 @@
|
||||
process_event
|
||||
register_device
|
||||
unregister_device
|
||||
51
daemons/dmeventd/Makefile.in
Normal file
51
daemons/dmeventd/Makefile.in
Normal file
@@ -0,0 +1,51 @@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of the device-mapper userspace tools.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU 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
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
TARGETS = dmevent dmeventd
|
||||
INSTALL_TYPE = install_dynamic
|
||||
|
||||
SOURCES = noop.c
|
||||
CLEAN_TARGETS = dmevent.o dmeventd.o
|
||||
|
||||
ifeq ("@LIB_SUFFIX@","dylib")
|
||||
LIB_SHARED = libdmeventdnoop.dylib
|
||||
else
|
||||
LIB_SHARED = libdmeventdnoop.so
|
||||
endif
|
||||
|
||||
LDFLAGS += -ldl -ldevmapper -lpthread -lmultilog
|
||||
|
||||
include ../make.tmpl
|
||||
|
||||
libdmeventdnoop.so: noop.o
|
||||
|
||||
dmevent: dmevent.o $(interfacedir)/libdevmapper.$(LIB_SUFFIX) $(top_srcdir)/lib/event/libdmevent.$(LIB_SUFFIX)
|
||||
$(CC) -o $@ dmevent.o $(LDFLAGS) \
|
||||
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog -ldmevent $(LIBS)
|
||||
|
||||
dmeventd: dmeventd.o $(interfacedir)/libdevmapper.$(LIB_SUFFIX) $(top_srcdir)/lib/event/libdmevent.$(LIB_SUFFIX)
|
||||
$(CC) -o $@ dmeventd.o $(LDFLAGS) \
|
||||
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog -ldmevent $(LIBS)
|
||||
|
||||
install: $(INSTALL_TYPE)
|
||||
|
||||
.PHONY: install_dynamic
|
||||
|
||||
install_dynamic: dmeventd
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) dmeventd $(sbindir)/dmeventd
|
||||
|
||||
194
daemons/dmeventd/dmevent.c
Normal file
194
daemons/dmeventd/dmevent.c
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "libdm-event.h"
|
||||
#include "libmultilog.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static enum event_type events = ALL_ERRORS; /* All until we can distinguish. */
|
||||
static char default_dso_name[] = "noop"; /* default DSO is noop */
|
||||
static int default_reg = 1; /* default action is register */
|
||||
static uint32_t timeout;
|
||||
|
||||
/* Display help. */
|
||||
static void print_usage(char *name)
|
||||
{
|
||||
char *cmd = strrchr(name, '/');
|
||||
|
||||
cmd = cmd ? cmd + 1 : name;
|
||||
printf("Usage::\n"
|
||||
"%s [options] <device>\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -d <dso> Specify the DSO to use.\n"
|
||||
" -h Print this usage.\n"
|
||||
" -l List registered devices.\n"
|
||||
" -r Register for event (default).\n"
|
||||
" -t <timeout> (un)register for timeout event.\n"
|
||||
" -u Unregister for event.\n"
|
||||
"\n", cmd);
|
||||
}
|
||||
|
||||
/* Parse command line arguments. */
|
||||
static int parse_argv(int argc, char **argv, char **dso_name_arg,
|
||||
char **device_arg, int *reg, int *list)
|
||||
{
|
||||
int c;
|
||||
const char *options = "d:hlrt:u";
|
||||
|
||||
while ((c = getopt(argc, argv, options)) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
*dso_name_arg = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'l':
|
||||
*list = 1;
|
||||
break;
|
||||
case 'r':
|
||||
*reg = 1;
|
||||
break;
|
||||
case 't':
|
||||
events = TIMEOUT;
|
||||
if (sscanf(optarg, "%"SCNu32, &timeout) != 1){
|
||||
fprintf(stderr, "invalid timeout '%s'\n",
|
||||
optarg);
|
||||
timeout = 0;
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
*reg = 0;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown option '%c'.\n"
|
||||
"Try '-h' for help.\n", c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
if (!*list) {
|
||||
fprintf(stderr, "You need to specify a device.\n");
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
*device_arg = argv[optind];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int list = 0, next = 0, ret, reg = default_reg;
|
||||
char *device, *device_arg = NULL, *dso_name, *dso_name_arg = NULL;
|
||||
|
||||
if (!parse_argv(argc, argv, &dso_name_arg, &device_arg, ®, &list))
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (device_arg) {
|
||||
if (!(device = strdup(device_arg)))
|
||||
exit(EXIT_FAILURE);
|
||||
} else
|
||||
device = NULL;
|
||||
|
||||
if (dso_name_arg) {
|
||||
if (!(dso_name = strdup(dso_name_arg)))
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
if (!(dso_name = strdup(default_dso_name)))
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* FIXME: use -v/-q options to set this */
|
||||
multilog_add_type(standard, NULL);
|
||||
multilog_init_verbose(standard, _LOG_DEBUG);
|
||||
|
||||
if (list) {
|
||||
while (1) {
|
||||
if ((ret= dm_get_registered_device(&dso_name, &device,
|
||||
&events, next)))
|
||||
break;
|
||||
printf("%s %s 0x%x", dso_name, device, events);
|
||||
if (events & TIMEOUT){
|
||||
if ((ret = dm_get_event_timeout(device,
|
||||
&timeout))) {
|
||||
ret = EXIT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
printf(" %"PRIu32"\n", timeout);
|
||||
} else
|
||||
printf("\n");
|
||||
if (device_arg)
|
||||
break;
|
||||
|
||||
next = 1;
|
||||
}
|
||||
|
||||
ret = (ret && device_arg) ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((ret = reg ? dm_register_for_event(dso_name, device, events) :
|
||||
dm_unregister_for_event(dso_name, device, events))) {
|
||||
fprintf(stderr, "Failed to %sregister %s: %s\n",
|
||||
reg ? "": "un", device, strerror(-ret));
|
||||
ret = EXIT_FAILURE;
|
||||
} else {
|
||||
if (reg && (events & TIMEOUT) &&
|
||||
((ret = dm_set_event_timeout(device, timeout)))){
|
||||
fprintf(stderr, "Failed to set timeout for %s: %s\n",
|
||||
device, strerror(-ret));
|
||||
ret = EXIT_FAILURE;
|
||||
} else {
|
||||
printf("%s %sregistered successfully.\n",
|
||||
device, reg ? "" : "un");
|
||||
ret = EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
multilog_del_type(standard);
|
||||
|
||||
if (device)
|
||||
free(device);
|
||||
if (dso_name)
|
||||
free(dso_name);
|
||||
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
1083
daemons/dmeventd/dmeventd.c
Normal file
1083
daemons/dmeventd/dmeventd.c
Normal file
File diff suppressed because it is too large
Load Diff
12
daemons/dmeventd/mktestdevices
Normal file
12
daemons/dmeventd/mktestdevices
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Create test devices for dmeventd
|
||||
#
|
||||
|
||||
trap "rm -f /tmp/tmp.$$" 0 1 2 3 15
|
||||
|
||||
echo "0 1024 zero" > /tmp/tmp.$$
|
||||
dmsetup create test /tmp/tmp.$$
|
||||
dmsetup create test1 /tmp/tmp.$$
|
||||
|
||||
kill -15 $$
|
||||
39
daemons/dmeventd/noop.c
Normal file
39
daemons/dmeventd/noop.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "libdm-event.h"
|
||||
#include "libmultilog.h"
|
||||
|
||||
|
||||
void process_event(char *device, enum event_type event)
|
||||
{
|
||||
log_err("[%s] %s(%d) - Device: %s, Event %d\n",
|
||||
__FILE__, __func__, __LINE__, device, event);
|
||||
}
|
||||
|
||||
int register_device(char *device)
|
||||
{
|
||||
log_err("[%s] %s(%d) - Device: %s\n",
|
||||
__FILE__, __func__, __LINE__, device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unregister_device(char *device)
|
||||
{
|
||||
log_err("[%s] %s(%d) - Device: %s\n",
|
||||
__FILE__, __func__, __LINE__, device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -258,11 +258,10 @@ activation {
|
||||
#
|
||||
# metadata {
|
||||
# Default number of copies of metadata to hold on each PV. 0, 1 or 2.
|
||||
# It's best to leave this at 2.
|
||||
# You might want to override it from the command line with 0 or 1
|
||||
# You might want to override it from the command line with 0
|
||||
# when running pvcreate on new PVs which are to be added to large VGs.
|
||||
|
||||
# pvmetadatacopies = 2
|
||||
# pvmetadatacopies = 1
|
||||
|
||||
# Approximate default size of on-disk metadata areas in sectors.
|
||||
# You should increase this if you have large volume groups or
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
../lib/filters/filter.h
|
||||
../lib/format1/format1.h
|
||||
../lib/format_pool/format_pool.h
|
||||
../lib/format_text/archiver.h
|
||||
../lib/format_text/format-text.h
|
||||
../lib/format_text/text_export.h
|
||||
../lib/format_text/text_import.h
|
||||
@@ -31,6 +32,7 @@
|
||||
../lib/log/log.h
|
||||
../lib/metadata/lv_alloc.h
|
||||
../lib/metadata/metadata.h
|
||||
../lib/metadata/pv_alloc.h
|
||||
../lib/metadata/segtype.h
|
||||
../lib/mm/dbg_malloc.h
|
||||
../lib/mm/memlock.h
|
||||
|
||||
@@ -54,6 +54,7 @@ SOURCES =\
|
||||
filters/filter-md.c \
|
||||
filters/filter.c \
|
||||
format_text/archive.c \
|
||||
format_text/archiver.c \
|
||||
format_text/export.c \
|
||||
format_text/flags.c \
|
||||
format_text/format-text.c \
|
||||
@@ -70,6 +71,7 @@ SOURCES =\
|
||||
metadata/merge.c \
|
||||
metadata/metadata.c \
|
||||
metadata/mirror.c \
|
||||
metadata/pv_manip.c \
|
||||
metadata/pv_map.c \
|
||||
metadata/segtype.c \
|
||||
metadata/snapshot_manip.c \
|
||||
|
||||
@@ -517,17 +517,15 @@ static int _lv_suspend_lv(struct logical_volume *lv)
|
||||
*/
|
||||
int lvs_in_vg_activated(struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
int count = 0;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (lv->status & VISIBLE_LV)
|
||||
count += (_lv_active(lv) == 1);
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if (lvl->lv->status & VISIBLE_LV)
|
||||
count += (_lv_active(lvl->lv) == 1);
|
||||
}
|
||||
|
||||
return count;
|
||||
@@ -535,17 +533,15 @@ int lvs_in_vg_activated(struct volume_group *vg)
|
||||
|
||||
int lvs_in_vg_opened(struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
int count = 0;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (lv->status & VISIBLE_LV)
|
||||
count += (_lv_open_count(lv) > 0);
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if (lvl->lv->status & VISIBLE_LV)
|
||||
count += (_lv_open_count(lvl->lv) > 0);
|
||||
}
|
||||
|
||||
return count;
|
||||
|
||||
@@ -727,6 +727,54 @@ static int _emit_target_line(struct dev_manager *dm, struct dm_task *dmt,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int compose_log_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
char *params, size_t paramsize, int *pos, int areas,
|
||||
uint32_t region_size)
|
||||
{
|
||||
int tw;
|
||||
char devbuf[10];
|
||||
char *name;
|
||||
struct dev_layer *dl;
|
||||
|
||||
if (!seg->log_lv)
|
||||
tw = lvm_snprintf(params, paramsize, "core 1 %u %u ",
|
||||
region_size, areas);
|
||||
else {
|
||||
if (!(name = build_dm_name(dm->mem, seg->log_lv->vg->name,
|
||||
seg->log_lv->name, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(dl = hash_lookup(dm->layers, seg->log_lv->lvid.s))) {
|
||||
log_error("device layer %s missing from hash",
|
||||
seg->log_lv->lvid.s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_format_dev(devbuf, sizeof(devbuf), dl->info.major,
|
||||
dl->info.minor)) {
|
||||
log_error("Failed to format device number as dm "
|
||||
"target (%u,%u)",
|
||||
dl->info.major, dl->info.minor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME add sync parm? */
|
||||
tw = lvm_snprintf(params, paramsize, "disk 2 %s %u %u ",
|
||||
devbuf, region_size, areas);
|
||||
}
|
||||
|
||||
if (tw < 0) {
|
||||
stack;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*pos += tw;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
char *params, size_t paramsize, int *pos, int start_area,
|
||||
int areas)
|
||||
@@ -740,24 +788,26 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
|
||||
for (s = start_area; s < areas; s++, *pos += tw) {
|
||||
trailing_space = (areas - s - 1) ? " " : "";
|
||||
if ((seg->area[s].type == AREA_PV &&
|
||||
(!seg->area[s].u.pv.pv || !seg->area[s].u.pv.pv->dev)) ||
|
||||
(seg->area[s].type == AREA_LV && !seg->area[s].u.lv.lv))
|
||||
if ((seg_type(seg, s) == AREA_PV &&
|
||||
(!seg_pvseg(seg, s) ||
|
||||
!seg_pv(seg, s) ||
|
||||
!seg_dev(seg, s))) ||
|
||||
(seg_type(seg, s) == AREA_LV && !seg_lv(seg, s)))
|
||||
tw = lvm_snprintf(params + *pos, paramsize - *pos,
|
||||
"%s 0%s", dm->stripe_filler,
|
||||
trailing_space);
|
||||
else if (seg->area[s].type == AREA_PV)
|
||||
else if (seg_type(seg, s) == AREA_PV)
|
||||
tw = lvm_snprintf(params + *pos, paramsize - *pos,
|
||||
"%s %" PRIu64 "%s",
|
||||
dev_name(seg->area[s].u.pv.pv->dev),
|
||||
(seg->area[s].u.pv.pv->pe_start +
|
||||
(esize * seg->area[s].u.pv.pe)),
|
||||
dev_name(seg_dev(seg, s)),
|
||||
(seg_pv(seg, s)->pe_start +
|
||||
(esize * seg_pe(seg, s))),
|
||||
trailing_space);
|
||||
else {
|
||||
if (!(dl = hash_lookup(dm->layers,
|
||||
seg->area[s].u.lv.lv->lvid.s))) {
|
||||
seg_lv(seg, s)->lvid.s))) {
|
||||
log_error("device layer %s missing from hash",
|
||||
seg->area[s].u.lv.lv->lvid.s);
|
||||
seg_lv(seg, s)->lvid.s);
|
||||
return 0;
|
||||
}
|
||||
if (!dm_format_dev
|
||||
@@ -770,7 +820,7 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
}
|
||||
tw = lvm_snprintf(params + *pos, paramsize - *pos,
|
||||
"%s %" PRIu64 "%s", devbuf,
|
||||
esize * seg->area[s].u.lv.le,
|
||||
esize * seg_le(seg, s),
|
||||
trailing_space);
|
||||
}
|
||||
|
||||
@@ -818,14 +868,12 @@ static int _emit_target(struct dev_manager *dm, struct dm_task *dmt,
|
||||
static int _populate_vanilla(struct dev_manager *dm,
|
||||
struct dm_task *dmt, struct dev_layer *dl)
|
||||
{
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
struct logical_volume *lv = dl->lv;
|
||||
|
||||
dm->pvmove_mirror_count = 0u;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (!_emit_target(dm, dmt, seg)) {
|
||||
log_error("Unable to build table for '%s'", lv->name);
|
||||
return 0;
|
||||
@@ -875,21 +923,23 @@ static int _populate_snapshot(struct dev_manager *dm,
|
||||
{
|
||||
char *origin, *cow;
|
||||
char params[PATH_MAX * 2 + 32];
|
||||
struct snapshot *s;
|
||||
struct lv_segment *snap_seg;
|
||||
struct dev_layer *dlo, *dlc;
|
||||
char devbufo[10], devbufc[10];
|
||||
uint64_t size;
|
||||
|
||||
if (!(s = find_cow(dl->lv))) {
|
||||
if (!(snap_seg = find_cow(dl->lv))) {
|
||||
log_error("Couldn't find snapshot for '%s'.", dl->lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(origin = _build_dlid(dm->mem, s->origin->lvid.s, "real"))) {
|
||||
if (!(origin = _build_dlid(dm->mem, snap_seg->origin->lvid.s,
|
||||
"real"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cow = _build_dlid(dm->mem, s->cow->lvid.s, "cow"))) {
|
||||
if (!(cow = _build_dlid(dm->mem, snap_seg->cow->lvid.s, "cow"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -908,27 +958,27 @@ static int _populate_snapshot(struct dev_manager *dm,
|
||||
if (!dm_format_dev(devbufo, sizeof(devbufo), dlo->info.major,
|
||||
dlo->info.minor)) {
|
||||
log_error("Couldn't create origin device parameters for '%s'.",
|
||||
s->origin->name);
|
||||
snap_seg->origin->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_format_dev(devbufc, sizeof(devbufc), dlc->info.major,
|
||||
dlc->info.minor)) {
|
||||
log_error("Couldn't create cow device parameters for '%s'.",
|
||||
s->cow->name);
|
||||
snap_seg->cow->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(params, sizeof(params), "%s %s P %d",
|
||||
devbufo, devbufc, s->chunk_size) == -1) {
|
||||
devbufo, devbufc, snap_seg->chunk_size) == -1) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("Adding target: 0 %" PRIu64 " snapshot %s",
|
||||
s->origin->size, params);
|
||||
if (!dm_task_add_target
|
||||
(dmt, UINT64_C(0), s->origin->size, "snapshot", params)) {
|
||||
size = (uint64_t) snap_seg->len * snap_seg->origin->vg->extent_size;
|
||||
|
||||
log_debug("Adding target: 0 %" PRIu64 " snapshot %s", size, params);
|
||||
if (!dm_task_add_target(dmt, UINT64_C(0), size, "snapshot", params)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1175,7 +1225,6 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv,
|
||||
* only one layer.
|
||||
*/
|
||||
struct dev_layer *dl, *dlr;
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
uint32_t s;
|
||||
|
||||
@@ -1193,14 +1242,22 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv,
|
||||
_set_flag(dl, TOPLEVEL);
|
||||
|
||||
/* Add dependencies for any LVs that segments refer to */
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (seg->log_lv &&
|
||||
!str_list_add(dm->mem, &dl->pre_create,
|
||||
_build_dlid(dm->mem, seg->log_lv->lvid.s,
|
||||
NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
// FIXME Check we don't want NOPROPAGATE here
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_LV)
|
||||
if (seg_type(seg, s) != AREA_LV)
|
||||
continue;
|
||||
if (!str_list_add(dm->mem, &dl->pre_create,
|
||||
_build_dlid(dm->mem,
|
||||
seg->area[s].u.lv.lv->
|
||||
seg_lv(seg, s)->
|
||||
lvid.s, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
@@ -1273,16 +1330,16 @@ static int _expand_origin_real(struct dev_manager *dm,
|
||||
static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *active;
|
||||
struct snapshot *s;
|
||||
struct list *sh;
|
||||
struct lv_segment *snap_seg;
|
||||
struct lv_list *lvl;
|
||||
|
||||
/*
|
||||
* We only need to create an origin layer if one of our
|
||||
* snapshots is in the active list
|
||||
*/
|
||||
list_iterate(sh, &dm->active_list) {
|
||||
active = list_item(sh, struct lv_list)->lv;
|
||||
if ((s = find_cow(active)) && (s->origin == lv))
|
||||
list_iterate_items(lvl, &dm->active_list) {
|
||||
active = lvl->lv;
|
||||
if ((snap_seg = find_cow(active)) && (snap_seg->origin == lv))
|
||||
return _expand_origin_real(dm, lv);
|
||||
}
|
||||
|
||||
@@ -1293,7 +1350,7 @@ static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv)
|
||||
}
|
||||
|
||||
static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv,
|
||||
struct snapshot *s)
|
||||
struct lv_segment *snap_seg)
|
||||
{
|
||||
/*
|
||||
* snapshot(org, cow)
|
||||
@@ -1330,13 +1387,15 @@ static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv,
|
||||
|
||||
/* add the dependency on the real origin device */
|
||||
if (!str_list_add(dm->mem, &dl->pre_create,
|
||||
_build_dlid(dm->mem, s->origin->lvid.s, "real"))) {
|
||||
_build_dlid(dm->mem, snap_seg->origin->lvid.s,
|
||||
"real"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* add the dependency on the visible origin device */
|
||||
if (!str_list_add(dm->mem, &dl->pre_suspend, s->origin->lvid.s)) {
|
||||
if (!str_list_add(dm->mem, &dl->pre_suspend,
|
||||
snap_seg->origin->lvid.s)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1349,13 +1408,13 @@ static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv,
|
||||
*/
|
||||
static int _expand_lv(struct dev_manager *dm, struct logical_volume *lv)
|
||||
{
|
||||
struct snapshot *s;
|
||||
struct lv_segment *snap_seg;
|
||||
|
||||
/*
|
||||
* FIXME: this doesn't cope with recursive snapshots yet.
|
||||
*/
|
||||
if ((s = find_cow(lv)))
|
||||
return _expand_snapshot(dm, lv, s);
|
||||
if ((snap_seg = find_cow(lv)))
|
||||
return _expand_snapshot(dm, lv, snap_seg);
|
||||
|
||||
else if (lv_is_origin(lv))
|
||||
return _expand_origin(dm, lv);
|
||||
@@ -1383,12 +1442,12 @@ static void _clear_marks(struct dev_manager *dm, int flag)
|
||||
static int _trace_layer_marks(struct dev_manager *dm, struct dev_layer *dl,
|
||||
int flag)
|
||||
{
|
||||
struct list *sh;
|
||||
struct str_list *strl;
|
||||
const char *dlid;
|
||||
struct dev_layer *dep;
|
||||
|
||||
list_iterate(sh, &dl->pre_create) {
|
||||
dlid = list_item(sh, struct str_list)->str;
|
||||
list_iterate_items(strl, &dl->pre_create) {
|
||||
dlid = strl->str;
|
||||
|
||||
if (!(dep = hash_lookup(dm->layers, dlid))) {
|
||||
log_error("Couldn't find device layer '%s'.", dlid);
|
||||
@@ -1438,14 +1497,14 @@ static int _trace_all_marks(struct dev_manager *dm, int flag)
|
||||
*/
|
||||
static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
struct dev_layer *dl;
|
||||
|
||||
list_iterate(lvh, lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
list_iterate_items(lvl, lvs) {
|
||||
if (lvl->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
if (!(dl = _lookup(dm, lv->lvid.s, NULL))) {
|
||||
if (!(dl = _lookup(dm, lvl->lv->lvid.s, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1463,12 +1522,12 @@ static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag)
|
||||
|
||||
static int _suspend_parents(struct dev_manager *dm, struct dev_layer *dl)
|
||||
{
|
||||
struct list *sh;
|
||||
struct str_list *strl;
|
||||
struct dev_layer *dep;
|
||||
const char *dlid;
|
||||
|
||||
list_iterate(sh, &dl->pre_suspend) {
|
||||
dlid = list_item(sh, struct str_list)->str;
|
||||
list_iterate_items(strl, &dl->pre_suspend) {
|
||||
dlid = strl->str;
|
||||
|
||||
if (!(dep = hash_lookup(dm->layers, dlid))) {
|
||||
log_debug("_suspend_parents couldn't find device "
|
||||
@@ -1497,12 +1556,12 @@ static int _suspend_parents(struct dev_manager *dm, struct dev_layer *dl)
|
||||
|
||||
static int _resume_with_deps(struct dev_manager *dm, struct dev_layer *dl)
|
||||
{
|
||||
struct list *sh;
|
||||
struct str_list *strl;
|
||||
struct dev_layer *dep;
|
||||
const char *dlid;
|
||||
|
||||
list_iterate(sh, &dl->pre_create) {
|
||||
dlid = list_item(sh, struct str_list)->str;
|
||||
list_iterate_items(strl, &dl->pre_create) {
|
||||
dlid = strl->str;
|
||||
|
||||
if (!(dep = hash_lookup(dm->layers, dlid))) {
|
||||
log_debug("_resume_with_deps couldn't find device "
|
||||
@@ -1535,7 +1594,7 @@ static int _resume_with_deps(struct dev_manager *dm, struct dev_layer *dl)
|
||||
*/
|
||||
static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
|
||||
{
|
||||
struct list *sh;
|
||||
struct str_list *strl;
|
||||
struct dev_layer *dep;
|
||||
const char *dlid;
|
||||
char *newname, *suffix;
|
||||
@@ -1547,8 +1606,8 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(sh, &dl->pre_create) {
|
||||
dlid = list_item(sh, struct str_list)->str;
|
||||
list_iterate_items(strl, &dl->pre_create) {
|
||||
dlid = strl->str;
|
||||
|
||||
if (!(dep = hash_lookup(dm->layers, dlid))) {
|
||||
log_error("Couldn't find device layer '%s'.", dlid);
|
||||
@@ -1604,15 +1663,15 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
|
||||
|
||||
static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lvt;
|
||||
struct lv_list *lvl;
|
||||
|
||||
/*
|
||||
* Build layers for complete vg.
|
||||
*/
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lvt = list_item(lvh, struct lv_list)->lv;
|
||||
if (!_expand_lv(dm, lvt)) {
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if (lvl->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
if (!_expand_lv(dm, lvl->lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1652,15 +1711,15 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm)
|
||||
{
|
||||
struct hash_node *hn;
|
||||
struct dev_layer *dl;
|
||||
struct list *sh;
|
||||
struct str_list *strl;
|
||||
const char *dlid;
|
||||
struct dev_layer *dep;
|
||||
|
||||
hash_iterate(hn, dm->layers) {
|
||||
dl = hash_get_data(dm->layers, hn);
|
||||
|
||||
list_iterate(sh, &dl->pre_suspend) {
|
||||
dlid = list_item(sh, struct str_list)->str;
|
||||
list_iterate_items(strl, &dl->pre_suspend) {
|
||||
dlid = strl->str;
|
||||
|
||||
if (!(dep = hash_lookup(dm->layers, dlid))) {
|
||||
log_debug("_populate_pre_suspend_lists: "
|
||||
@@ -1675,8 +1734,8 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm)
|
||||
}
|
||||
}
|
||||
|
||||
list_iterate(sh, &dl->pre_create) {
|
||||
dlid = list_item(sh, struct str_list)->str;
|
||||
list_iterate_items(strl, &dl->pre_create) {
|
||||
dlid = strl->str;
|
||||
|
||||
if (!(dep = hash_lookup(dm->layers, dlid))) {
|
||||
log_debug("_populate_pre_suspend_lists: "
|
||||
@@ -1701,6 +1760,7 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm)
|
||||
static int _remove_old_layers(struct dev_manager *dm)
|
||||
{
|
||||
int change;
|
||||
struct dl_list *dll;
|
||||
struct list *rh, *n;
|
||||
struct dev_layer *dl;
|
||||
|
||||
@@ -1723,10 +1783,8 @@ static int _remove_old_layers(struct dev_manager *dm)
|
||||
} while (change);
|
||||
|
||||
if (!list_empty(&dm->remove_list)) {
|
||||
list_iterate(rh, &dm->remove_list) {
|
||||
dl = list_item(rh, struct dl_list)->dl;
|
||||
log_error("Couldn't deactivate device %s", dl->name);
|
||||
}
|
||||
list_iterate_items(dll, &dm->remove_list)
|
||||
log_error("Couldn't deactivate device %s", dll->dl->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1913,14 +1971,14 @@ static int _add_lv(struct pool *mem,
|
||||
static int _add_lvs(struct pool *mem,
|
||||
struct list *head, struct logical_volume *origin)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct snapshot *s;
|
||||
struct list *lvh;
|
||||
struct lv_segment *snap_seg;
|
||||
struct lv_list *lvl;
|
||||
|
||||
list_iterate(lvh, &origin->vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if ((s = find_cow(lv)) && s->origin == origin)
|
||||
if (!_add_lv(mem, head, lv))
|
||||
list_iterate_items(lvl, &origin->vg->lvs) {
|
||||
if (lvl->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
if ((snap_seg = find_cow(lvl->lv)) && snap_seg->origin == origin)
|
||||
if (!_add_lv(mem, head, lvl->lv))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1929,13 +1987,11 @@ static int _add_lvs(struct pool *mem,
|
||||
|
||||
static void _remove_lv(struct list *head, struct logical_volume *lv)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct lv_list *lvl;
|
||||
|
||||
list_iterate(lvh, head) {
|
||||
lvl = list_item(lvh, struct lv_list);
|
||||
list_iterate_items(lvl, head) {
|
||||
if (lvl->lv == lv) {
|
||||
list_del(lvh);
|
||||
list_del(&lvl->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1944,30 +2000,32 @@ static void _remove_lv(struct list *head, struct logical_volume *lv)
|
||||
static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *active, *old_origin;
|
||||
struct snapshot *s;
|
||||
struct list *sh, *active_head;
|
||||
struct lv_segment *snap_seg;
|
||||
struct list *active_head;
|
||||
struct lv_list *lvl;
|
||||
|
||||
active_head = &dm->active_list;
|
||||
|
||||
/* Remove any snapshots with given origin */
|
||||
list_iterate(sh, active_head) {
|
||||
active = list_item(sh, struct lv_list)->lv;
|
||||
if ((s = find_cow(active)) && s->origin == lv) {
|
||||
list_iterate_items(lvl, active_head) {
|
||||
active = lvl->lv;
|
||||
if ((snap_seg = find_cow(active)) && snap_seg->origin == lv) {
|
||||
_remove_lv(active_head, active);
|
||||
}
|
||||
}
|
||||
|
||||
_remove_lv(active_head, lv);
|
||||
|
||||
if (!(s = find_cow(lv)))
|
||||
if (!(snap_seg = find_cow(lv)))
|
||||
return 1;
|
||||
|
||||
old_origin = s->origin;
|
||||
old_origin = snap_seg->origin;
|
||||
|
||||
/* Was this the last active snapshot with this origin? */
|
||||
list_iterate(sh, active_head) {
|
||||
active = list_item(sh, struct lv_list)->lv;
|
||||
if ((s = find_cow(active)) && s->origin == old_origin) {
|
||||
list_iterate_items(lvl, active_head) {
|
||||
active = lvl->lv;
|
||||
if ((snap_seg = find_cow(active)) &&
|
||||
snap_seg->origin == old_origin) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -1979,15 +2037,17 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *suspended;
|
||||
struct snapshot *s;
|
||||
struct list *sh, *suspend_head;
|
||||
struct lv_segment *snap_seg;
|
||||
struct list *suspend_head;
|
||||
struct lv_list *lvl;
|
||||
|
||||
suspend_head = &dm->suspend_list;
|
||||
|
||||
/* Remove from list any snapshots with given origin */
|
||||
list_iterate(sh, suspend_head) {
|
||||
suspended = list_item(sh, struct lv_list)->lv;
|
||||
if ((s = find_cow(suspended)) && s->origin == lv) {
|
||||
list_iterate_items(lvl, suspend_head) {
|
||||
suspended = lvl->lv;
|
||||
if ((snap_seg = find_cow(suspended)) &&
|
||||
snap_seg->origin == lv) {
|
||||
_remove_lv(suspend_head, suspended);
|
||||
}
|
||||
}
|
||||
@@ -2000,13 +2060,13 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
|
||||
static int _targets_present(struct dev_manager *dm, struct list *lvs)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct list *lvh, *segh;
|
||||
struct lv_list *lvl;
|
||||
struct segment_type *segtype;
|
||||
struct lv_segment *seg;
|
||||
int snapshots = 0, mirrors = 0;
|
||||
|
||||
list_iterate(lvh, lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
list_iterate_items(lvl, lvs) {
|
||||
lv = lvl->lv;
|
||||
|
||||
if (!snapshots)
|
||||
if (lv_is_cow(lv) || lv_is_origin(lv))
|
||||
@@ -2017,8 +2077,7 @@ static int _targets_present(struct dev_manager *dm, struct list *lvs)
|
||||
mirrors = 1;
|
||||
|
||||
if (lv->status & VIRTUAL) {
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (seg->segtype->ops->target_present &&
|
||||
!seg->segtype->ops->target_present()) {
|
||||
log_error("Can't expand LV: %s target "
|
||||
@@ -2067,14 +2126,14 @@ static int _targets_present(struct dev_manager *dm, struct list *lvs)
|
||||
static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
|
||||
{
|
||||
char *dlid;
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
struct dev_layer *dl;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if (lvl->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) {
|
||||
if (!(dlid = _build_dlid(dm->mem, lvl->lv->lvid.s, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -2083,16 +2142,16 @@ static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
|
||||
pool_free(dm->mem, dlid);
|
||||
|
||||
if (dl) {
|
||||
log_debug("Found active lv %s%s", lv->name,
|
||||
log_debug("Found active lv %s%s", lvl->lv->name,
|
||||
dl->info.suspended ? " (suspended)" : "");
|
||||
|
||||
if (!_add_lv(dm->mem, &dm->active_list, lv)) {
|
||||
if (!_add_lv(dm->mem, &dm->active_list, lvl->lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dl->info.suspended) {
|
||||
if (!_add_lv(dm->mem, &dm->suspend_list, lv)) {
|
||||
if (!_add_lv(dm->mem, &dm->suspend_list, lvl->lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ static int _rm_dir(const char *dev_dir, const char *vg_name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_empty_dir(vg_path)) {
|
||||
if (dir_exists(vg_path) && is_empty_dir(vg_path)) {
|
||||
log_very_verbose("Removing directory %s", vg_path);
|
||||
rmdir(vg_path);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,12 @@
|
||||
struct dev_manager;
|
||||
struct lv_segment;
|
||||
|
||||
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg, char *params, size_t paramsize, int *pos,
|
||||
int start_area, int areas);
|
||||
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
char *params, size_t paramsize, int *pos,
|
||||
int start_area, int areas);
|
||||
|
||||
int compose_log_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
char *params, size_t paramsize, int *pos, int areas,
|
||||
uint32_t region_size);
|
||||
|
||||
#endif
|
||||
|
||||
44
lib/cache/lvmcache.c
vendored
44
lib/cache/lvmcache.c
vendored
@@ -104,10 +104,31 @@ struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname)
|
||||
const struct format_type *fmt_from_vgname(const char *vgname)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_info *info;
|
||||
struct label *label;
|
||||
struct list *devh, *tmp;
|
||||
struct list devs;
|
||||
struct device_list *devl;
|
||||
|
||||
if (!(vginfo = vginfo_from_vgname(vgname)))
|
||||
return NULL;
|
||||
|
||||
/* This function is normally called before reading metadata so
|
||||
* we check cached labels here. Unfortunately vginfo is volatile. */
|
||||
list_init(&devs);
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
devl = dbg_malloc(sizeof(*devl));
|
||||
devl->dev = info->dev;
|
||||
list_add(&devs, &devl->list);
|
||||
}
|
||||
|
||||
list_iterate_safe(devh, tmp, &devs) {
|
||||
devl = list_item(devh, struct device_list);
|
||||
label_read(devl->dev, &label);
|
||||
list_del(&devl->list);
|
||||
dbg_free(devl);
|
||||
}
|
||||
|
||||
return vginfo->fmt;
|
||||
}
|
||||
|
||||
@@ -166,7 +187,6 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
struct label *label;
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
struct list *fmth;
|
||||
struct format_type *fmt;
|
||||
|
||||
static int _scanning_in_progress = 0;
|
||||
@@ -188,7 +208,7 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(iter = dev_iter_create(cmd->filter))) {
|
||||
if (!(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1: 0))) {
|
||||
log_error("dev_iter creation failed");
|
||||
goto out;
|
||||
}
|
||||
@@ -201,8 +221,7 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
_has_scanned = 1;
|
||||
|
||||
/* Perform any format-specific scanning e.g. text files */
|
||||
list_iterate(fmth, &cmd->formats) {
|
||||
fmt = list_item(fmth, struct format_type);
|
||||
list_iterate_items(fmt, &cmd->formats) {
|
||||
if (fmt->ops->scan && !fmt->ops->scan(fmt))
|
||||
goto out;
|
||||
}
|
||||
@@ -266,7 +285,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
if (memlock())
|
||||
return NULL;
|
||||
|
||||
lvmcache_label_scan(cmd, 1);
|
||||
lvmcache_label_scan(cmd, 2);
|
||||
|
||||
/* Try again */
|
||||
if ((info = info_from_pvid((char *) pvid))) {
|
||||
@@ -403,23 +422,24 @@ int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
|
||||
/* FIXME Check consistency of list! */
|
||||
vginfo->fmt = info->fmt;
|
||||
|
||||
log_debug("lvmcache: %s now %s%s", dev_name(info->dev),
|
||||
*vgname ? "in VG " : "orphaned", vgname);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lvmcache_update_vg(struct volume_group *vg)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct physical_volume *pv;
|
||||
struct pv_list *pvl;
|
||||
struct lvmcache_info *info;
|
||||
char pvid_s[ID_LEN + 1];
|
||||
int vgid_updated = 0;
|
||||
|
||||
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1);
|
||||
/* FIXME Could pv->dev->pvid ever be different? */
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1);
|
||||
/* FIXME Could pvl->pv->dev->pvid ever be different? */
|
||||
if ((info = info_from_pvid(pvid_s))) {
|
||||
lvmcache_update_vgname(info, vg->name);
|
||||
if (!vgid_updated) {
|
||||
@@ -551,6 +571,8 @@ static void _lvmcache_destroy_lockname(int present)
|
||||
|
||||
void lvmcache_destroy(void)
|
||||
{
|
||||
log_verbose("Wiping internal VG cache");
|
||||
|
||||
_has_scanned = 0;
|
||||
|
||||
if (_vgid_hash) {
|
||||
|
||||
6
lib/cache/lvmcache.h
vendored
6
lib/cache/lvmcache.h
vendored
@@ -36,9 +36,10 @@ struct volume_group;
|
||||
struct lvmcache_vginfo {
|
||||
struct list list; /* Join these vginfos together */
|
||||
struct list infos; /* List head for lvmcache_infos */
|
||||
const struct format_type *fmt;
|
||||
char *vgname; /* "" == orphan */
|
||||
char vgid[ID_LEN + 1];
|
||||
const struct format_type *fmt;
|
||||
char _padding[7];
|
||||
};
|
||||
|
||||
struct lvmcache_info {
|
||||
@@ -56,7 +57,8 @@ struct lvmcache_info {
|
||||
int lvmcache_init(void);
|
||||
void lvmcache_destroy(void);
|
||||
|
||||
/* Set full_scan to 1 to reread every filtered device label */
|
||||
/* Set full_scan to 1 to reread every filtered device label or
|
||||
* 2 to rescan /dev for new devices */
|
||||
int lvmcache_label_scan(struct cmd_context *cmd, int full_scan);
|
||||
|
||||
/* Add/delete a device */
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#include "str_list.h"
|
||||
#include "segtype.h"
|
||||
#include "lvmcache.h"
|
||||
#include "dev-cache.h"
|
||||
#include "archiver.h"
|
||||
|
||||
#ifdef HAVE_LIBDL
|
||||
#include "sharedlib.h"
|
||||
@@ -181,6 +183,12 @@ static int _process_config(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*cmd->proc_dir && !dir_exists(cmd->proc_dir)) {
|
||||
log_error("Warning: proc dir %s not found - some checks will be bypassed",
|
||||
cmd->proc_dir);
|
||||
cmd->proc_dir[0] = '\0';
|
||||
}
|
||||
|
||||
/* activation? */
|
||||
cmd->default_settings.activation = find_config_int(cmd->cft->root,
|
||||
"global/activation",
|
||||
@@ -487,6 +495,24 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(cmd->cft->root, "devices/loopfiles")))
|
||||
return 1;
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_error("Invalid string in config file: "
|
||||
"devices/loopfiles");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dev_cache_add_loopfile(cv->v.str)) {
|
||||
log_error("Failed to add loopfile %s to internal "
|
||||
"device cache", cv->v.str);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -596,7 +622,6 @@ static int _init_formats(struct cmd_context *cmd)
|
||||
const char *format;
|
||||
|
||||
struct format_type *fmt;
|
||||
struct list *fmth;
|
||||
|
||||
#ifdef HAVE_LIBDL
|
||||
const struct config_node *cn;
|
||||
@@ -663,8 +688,7 @@ static int _init_formats(struct cmd_context *cmd)
|
||||
format = find_config_str(cmd->cft->root, "global/format",
|
||||
DEFAULT_FORMAT);
|
||||
|
||||
list_iterate(fmth, &cmd->formats) {
|
||||
fmt = list_item(fmth, struct format_type);
|
||||
list_iterate_items(fmt, &cmd->formats) {
|
||||
if (!strcasecmp(fmt->name, format) ||
|
||||
(fmt->alias && !strcasecmp(fmt->alias, format))) {
|
||||
cmd->default_settings.fmt = fmt;
|
||||
@@ -789,6 +813,69 @@ static int _init_hostname(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_backup(struct cmd_context *cmd)
|
||||
{
|
||||
uint32_t days, min;
|
||||
char default_dir[PATH_MAX];
|
||||
const char *dir;
|
||||
|
||||
if (!cmd->sys_dir) {
|
||||
log_warn("WARNING: Metadata changes will NOT be backed up");
|
||||
backup_init(cmd, "");
|
||||
archive_init(cmd, "", 0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* set up archiving */
|
||||
cmd->default_settings.archive =
|
||||
find_config_bool(cmd->cft->root, "backup/archive",
|
||||
DEFAULT_ARCHIVE_ENABLED);
|
||||
|
||||
days = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_days",
|
||||
DEFAULT_ARCHIVE_DAYS);
|
||||
|
||||
min = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_min",
|
||||
DEFAULT_ARCHIVE_NUMBER);
|
||||
|
||||
if (lvm_snprintf
|
||||
(default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
|
||||
DEFAULT_ARCHIVE_SUBDIR) == -1) {
|
||||
log_err("Couldn't create default archive path '%s/%s'.",
|
||||
cmd->sys_dir, DEFAULT_ARCHIVE_SUBDIR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dir = find_config_str(cmd->cft->root, "backup/archive_dir",
|
||||
default_dir);
|
||||
|
||||
if (!archive_init(cmd, dir, days, min)) {
|
||||
log_debug("backup_init failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set up the backup */
|
||||
cmd->default_settings.backup =
|
||||
find_config_bool(cmd->cft->root, "backup/backup",
|
||||
DEFAULT_BACKUP_ENABLED);
|
||||
|
||||
if (lvm_snprintf
|
||||
(default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
|
||||
DEFAULT_BACKUP_SUBDIR) == -1) {
|
||||
log_err("Couldn't create default backup path '%s/%s'.",
|
||||
cmd->sys_dir, DEFAULT_BACKUP_SUBDIR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dir = find_config_str(cmd->cft->root, "backup/backup_dir", default_dir);
|
||||
|
||||
if (!backup_init(cmd, dir)) {
|
||||
log_debug("backup_init failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Entry point */
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
{
|
||||
@@ -825,8 +912,13 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
goto error;
|
||||
|
||||
/* Create system directory if it doesn't already exist */
|
||||
if (*cmd->sys_dir && !create_dir(cmd->sys_dir))
|
||||
if (*cmd->sys_dir && !create_dir(cmd->sys_dir)) {
|
||||
log_error("Failed to create LVM2 system dir for metadata backups, config "
|
||||
"files and internal cache.");
|
||||
log_error("Set environment variable LVM_SYSTEM_DIR to alternative location "
|
||||
"or empty string.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(cmd->libmem = pool_create("library", 4 * 1024))) {
|
||||
log_error("Library memory pool creation failed");
|
||||
@@ -872,6 +964,9 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
if (!_init_segtypes(cmd))
|
||||
goto error;
|
||||
|
||||
if (!_init_backup(cmd))
|
||||
goto error;
|
||||
|
||||
cmd->current_settings = cmd->default_settings;
|
||||
|
||||
cmd->config_valid = 1;
|
||||
@@ -982,6 +1077,8 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
||||
if (cmd->dump_filter)
|
||||
persistent_filter_dump(cmd->filter);
|
||||
|
||||
archive_exit(cmd);
|
||||
backup_exit(cmd);
|
||||
activation_exit();
|
||||
lvmcache_destroy();
|
||||
label_exit();
|
||||
|
||||
@@ -32,20 +32,20 @@ struct config_info {
|
||||
int syslog;
|
||||
int activation;
|
||||
int suffix;
|
||||
uint64_t unit_factor;
|
||||
char unit_type;
|
||||
const char *msg_prefix;
|
||||
int cmd_name; /* Show command name? */
|
||||
|
||||
int archive; /* should we archive ? */
|
||||
int backup; /* should we backup ? */
|
||||
|
||||
const char *msg_prefix;
|
||||
struct format_type *fmt;
|
||||
|
||||
uint64_t unit_factor;
|
||||
int cmd_name; /* Show command name? */
|
||||
mode_t umask;
|
||||
char unit_type;
|
||||
char _padding[1];
|
||||
};
|
||||
|
||||
struct config_tree;
|
||||
struct archive_params;
|
||||
struct backup_params;
|
||||
|
||||
/* FIXME Split into tool & library contexts */
|
||||
/* command-instance-related variables needed by library */
|
||||
@@ -75,6 +75,9 @@ struct cmd_context {
|
||||
struct config_info default_settings;
|
||||
struct config_info current_settings;
|
||||
|
||||
struct archive_params *archive_params;
|
||||
struct backup_params *backup_params;
|
||||
|
||||
/* List of defined tags */
|
||||
struct list tags;
|
||||
int hosttags;
|
||||
|
||||
@@ -235,7 +235,7 @@ int read_config_file(struct config_tree *cft)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
|
||||
if (!(dev = dev_create_file(c->filename, NULL, NULL, 1))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -91,19 +91,22 @@
|
||||
#define DEFAULT_REP_HEADINGS 1
|
||||
#define DEFAULT_REP_SEPARATOR " "
|
||||
|
||||
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,copy_percent"
|
||||
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,mirror_log,copy_percent"
|
||||
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
|
||||
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
|
||||
#define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"
|
||||
#define DEFAULT_PVSEGS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
|
||||
|
||||
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,lv_uuid"
|
||||
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,mirror_log,lv_uuid"
|
||||
#define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid"
|
||||
#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid"
|
||||
#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
|
||||
#define DEFAULT_PVSEGS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
|
||||
|
||||
#define DEFAULT_LVS_SORT "vg_name,lv_name"
|
||||
#define DEFAULT_VGS_SORT "vg_name"
|
||||
#define DEFAULT_PVS_SORT "pv_name"
|
||||
#define DEFAULT_SEGS_SORT "vg_name,lv_name,seg_start"
|
||||
#define DEFAULT_PVSEGS_SORT "pv_name,pvseg_start"
|
||||
|
||||
#endif /* _LVM_DEFAULTS_H */
|
||||
|
||||
@@ -18,17 +18,30 @@
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* A list consists of a list head plus elements.
|
||||
* Each element has 'next' and 'previous' pointers.
|
||||
* The list head's pointers point to the first and the last element.
|
||||
*/
|
||||
|
||||
struct list {
|
||||
struct list *n, *p;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialise a list before use.
|
||||
* The list head's next and previous pointers point back to itself.
|
||||
*/
|
||||
#define LIST_INIT(name) struct list name = { &(name), &(name) }
|
||||
|
||||
static inline void list_init(struct list *head)
|
||||
{
|
||||
head->n = head->p = head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert an element before 'head'.
|
||||
* If 'head' is the list head, this adds an element to the end of the list.
|
||||
*/
|
||||
static inline void list_add(struct list *head, struct list *elem)
|
||||
{
|
||||
assert(head->n);
|
||||
@@ -40,6 +53,10 @@ static inline void list_add(struct list *head, struct list *elem)
|
||||
head->p = elem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert an element after 'head'.
|
||||
* If 'head' is the list head, this adds an element to the front of the list.
|
||||
*/
|
||||
static inline void list_add_h(struct list *head, struct list *elem)
|
||||
{
|
||||
assert(head->n);
|
||||
@@ -51,53 +68,162 @@ static inline void list_add_h(struct list *head, struct list *elem)
|
||||
head->n = elem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete an element from its list.
|
||||
* Note that this doesn't change the element itself - it may still be safe
|
||||
* to follow its pointers.
|
||||
*/
|
||||
static inline void list_del(struct list *elem)
|
||||
{
|
||||
elem->n->p = elem->p;
|
||||
elem->p->n = elem->n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the list empty?
|
||||
*/
|
||||
static inline int list_empty(struct list *head)
|
||||
{
|
||||
return head->n == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this the first element of the list?
|
||||
*/
|
||||
static inline int list_start(struct list *head, struct list *elem)
|
||||
{
|
||||
return elem->p == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this the last element of the list?
|
||||
*/
|
||||
static inline int list_end(struct list *head, struct list *elem)
|
||||
{
|
||||
return elem->n == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return first element of the list or NULL if empty
|
||||
*/
|
||||
static inline struct list *list_first(struct list *head)
|
||||
{
|
||||
return (list_empty(head) ? NULL : head->n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return last element of the list or NULL if empty
|
||||
*/
|
||||
static inline struct list *list_last(struct list *head)
|
||||
{
|
||||
return (list_empty(head) ? NULL : head->p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the previous element of the list, or NULL if we've reached the start.
|
||||
*/
|
||||
static inline struct list *list_prev(struct list *head, struct list *elem)
|
||||
{
|
||||
return (list_start(head, elem) ? NULL : elem->p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the next element of the list, or NULL if we've reached the end.
|
||||
*/
|
||||
static inline struct list *list_next(struct list *head, struct list *elem)
|
||||
{
|
||||
return (list_end(head, elem) ? NULL : elem->n);
|
||||
}
|
||||
|
||||
#define list_item(v, t) \
|
||||
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list))
|
||||
/*
|
||||
* Given the address v of an instance of 'struct list' called 'head'
|
||||
* contained in a structure of type t, return the containing structure.
|
||||
*/
|
||||
#define list_struct_base(v, t, head) \
|
||||
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->head))
|
||||
|
||||
#define list_struct_base(v, t, h) \
|
||||
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->h))
|
||||
/*
|
||||
* Given the address v of an instance of 'struct list list' contained in
|
||||
* a structure of type t, return the containing structure.
|
||||
*/
|
||||
#define list_item(v, t) list_struct_base((v), t, list)
|
||||
|
||||
/* Given a known element in a known structure, locate another */
|
||||
/*
|
||||
* Given the address v of one known element e in a known structure of type t,
|
||||
* return another element f.
|
||||
*/
|
||||
#define struct_field(v, t, e, f) \
|
||||
(((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f)
|
||||
|
||||
/* Given a known element in a known structure, locate the list head */
|
||||
/*
|
||||
* Given the address v of a known element e in a known structure of type t,
|
||||
* return the list head 'list'
|
||||
*/
|
||||
#define list_head(v, t, e) struct_field(v, t, e, list)
|
||||
|
||||
/*
|
||||
* Set v to each element of a list in turn.
|
||||
*/
|
||||
#define list_iterate(v, head) \
|
||||
for (v = (head)->n; v != head; v = v->n)
|
||||
|
||||
/*
|
||||
* Set v to each element in a list in turn, starting from the element
|
||||
* in front of 'start'.
|
||||
* You can use this to 'unwind' a list_iterate and back out actions on
|
||||
* already-processed elements.
|
||||
* If 'start' is 'head' it walks the list backwards.
|
||||
*/
|
||||
#define list_uniterate(v, head, start) \
|
||||
for (v = (start)->p; v != head; v = v->p)
|
||||
|
||||
/*
|
||||
* A safe way to walk a list and delete and free some elements along
|
||||
* the way.
|
||||
* t must be defined as a temporary variable of the same type as v.
|
||||
*/
|
||||
#define list_iterate_safe(v, t, head) \
|
||||
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
|
||||
|
||||
#define list_iterate_items(v, head) \
|
||||
for (v = list_item((head)->n, typeof(*v)); &v->list != (head); \
|
||||
v = list_item(v->list.n, typeof(*v)))
|
||||
/*
|
||||
* Walk a list, setting 'v' in turn to the containing structure of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The 'struct list' variable within the containing structure is 'field'.
|
||||
*/
|
||||
#define list_iterate_items_gen(v, head, field) \
|
||||
for (v = list_struct_base((head)->n, typeof(*v), field); \
|
||||
&v->field != (head); \
|
||||
v = list_struct_base(v->field.n, typeof(*v), field))
|
||||
|
||||
/*
|
||||
* Walk a list, setting 'v' in turn to the containing structure of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The list should be 'struct list list' within the containing structure.
|
||||
*/
|
||||
#define list_iterate_items(v, head) list_iterate_items_gen(v, (head), list)
|
||||
|
||||
/*
|
||||
* Walk a list backwards, setting 'v' in turn to the containing structure
|
||||
* of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The 'struct list' variable within the containing structure is 'field'.
|
||||
*/
|
||||
#define list_iterate_back_items_gen(v, head, field) \
|
||||
for (v = list_struct_base((head)->p, typeof(*v), field); \
|
||||
&v->field != (head); \
|
||||
v = list_struct_base(v->field.p, typeof(*v), field))
|
||||
|
||||
/*
|
||||
* Walk a list backwards, setting 'v' in turn to the containing structure
|
||||
* of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The list should be 'struct list list' within the containing structure.
|
||||
*/
|
||||
#define list_iterate_back_items(v, head) list_iterate_back_items_gen(v, (head), list)
|
||||
|
||||
/*
|
||||
* Return the number of elements in a list by walking it.
|
||||
*/
|
||||
static inline unsigned int list_size(const struct list *head)
|
||||
{
|
||||
unsigned int s = 0;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
/* Define some portable printing types */
|
||||
#define PRIsize_t "Zu"
|
||||
#define PRIsize_t "zu"
|
||||
|
||||
struct str_list {
|
||||
struct list list;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "lvm-types.h"
|
||||
#include "btree.h"
|
||||
#include "filter.h"
|
||||
#include "filter-persistent.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
@@ -43,39 +44,60 @@ static struct {
|
||||
|
||||
int has_scanned;
|
||||
struct list dirs;
|
||||
struct list files;
|
||||
|
||||
} _cache;
|
||||
|
||||
#define _alloc(x) pool_alloc(_cache.mem, (x))
|
||||
#define _alloc(x) pool_zalloc(_cache.mem, (x))
|
||||
#define _free(x) pool_free(_cache.mem, (x))
|
||||
#define _strdup(x) pool_strdup(_cache.mem, (x))
|
||||
|
||||
static int _insert(const char *path, int rec);
|
||||
|
||||
struct device *dev_create_file(const char *filename, struct device *dev,
|
||||
struct str_list *alias)
|
||||
struct str_list *alias, int use_malloc)
|
||||
{
|
||||
int allocate = !dev;
|
||||
|
||||
if (allocate && !(dev = dbg_malloc(sizeof(*dev)))) {
|
||||
log_error("struct device allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
if (allocate && !(alias = dbg_malloc(sizeof(*alias)))) {
|
||||
log_error("struct str_list allocation failed");
|
||||
dbg_free(dev);
|
||||
return NULL;
|
||||
}
|
||||
if (!(alias->str = dbg_strdup(filename))) {
|
||||
log_error("filename strdup failed");
|
||||
if (allocate) {
|
||||
dbg_free(dev);
|
||||
dbg_free(alias);
|
||||
if (allocate) {
|
||||
if (use_malloc) {
|
||||
if (!(dev = dbg_malloc(sizeof(*dev)))) {
|
||||
log_error("struct device allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
if (!(alias = dbg_malloc(sizeof(*alias)))) {
|
||||
log_error("struct str_list allocation failed");
|
||||
dbg_free(dev);
|
||||
return NULL;
|
||||
}
|
||||
if (!(alias->str = dbg_strdup(filename))) {
|
||||
log_error("filename strdup failed");
|
||||
dbg_free(dev);
|
||||
dbg_free(alias);
|
||||
return NULL;
|
||||
}
|
||||
dev->flags = DEV_ALLOCED;
|
||||
} else {
|
||||
if (!(dev = _alloc(sizeof(*dev)))) {
|
||||
log_error("struct device allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
if (!(alias = _alloc(sizeof(*alias)))) {
|
||||
log_error("struct str_list allocation failed");
|
||||
_free(dev);
|
||||
return NULL;
|
||||
}
|
||||
if (!(alias->str = _strdup(filename))) {
|
||||
log_error("filename strdup failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else if (!(alias->str = dbg_strdup(filename))) {
|
||||
log_error("filename strdup failed");
|
||||
return NULL;
|
||||
}
|
||||
dev->flags = DEV_REGULAR;
|
||||
if (allocate)
|
||||
dev->flags |= DEV_ALLOCED;
|
||||
|
||||
dev->flags |= DEV_REGULAR;
|
||||
list_init(&dev->aliases);
|
||||
list_add(&dev->aliases, &alias->list);
|
||||
dev->end = UINT64_C(0);
|
||||
@@ -174,7 +196,7 @@ static int _compare_paths(const char *path0, const char *path1)
|
||||
static int _add_alias(struct device *dev, const char *path)
|
||||
{
|
||||
struct str_list *sl = _alloc(sizeof(*sl));
|
||||
struct list *ah;
|
||||
struct str_list *strl;
|
||||
const char *oldpath;
|
||||
int prefer_old = 1;
|
||||
|
||||
@@ -184,9 +206,9 @@ static int _add_alias(struct device *dev, const char *path)
|
||||
}
|
||||
|
||||
/* Is name already there? */
|
||||
list_iterate(ah, &dev->aliases) {
|
||||
if (!strcmp(list_item(ah, struct str_list)->str, path)) {
|
||||
stack;
|
||||
list_iterate_items(strl, &dev->aliases) {
|
||||
if (!strcmp(strl->str, path)) {
|
||||
log_debug("%s: Already in device cache", path);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -220,12 +242,25 @@ static int _add_alias(struct device *dev, const char *path)
|
||||
static int _insert_dev(const char *path, dev_t d)
|
||||
{
|
||||
struct device *dev;
|
||||
static dev_t loopfile_count = 0;
|
||||
int loopfile = 0;
|
||||
|
||||
/* Generate pretend device numbers for loopfiles */
|
||||
if (!d) {
|
||||
d = ++loopfile_count;
|
||||
loopfile = 1;
|
||||
}
|
||||
|
||||
/* is this device already registered ? */
|
||||
if (!(dev = (struct device *) btree_lookup(_cache.devices,
|
||||
(uint32_t) d))) {
|
||||
/* create new device */
|
||||
if (!(dev = _dev_create(d))) {
|
||||
if (loopfile) {
|
||||
if (!(dev = dev_create_file(path, NULL, NULL, 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
} else if (!(dev = _dev_create(d))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -237,7 +272,7 @@ static int _insert_dev(const char *path, dev_t d)
|
||||
}
|
||||
}
|
||||
|
||||
if (!_add_alias(dev, path)) {
|
||||
if (!loopfile && !_add_alias(dev, path)) {
|
||||
log_err("Couldn't add alias to dev cache.");
|
||||
return 0;
|
||||
}
|
||||
@@ -313,6 +348,28 @@ static int _insert_dir(const char *dir)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _insert_file(const char *path)
|
||||
{
|
||||
struct stat info;
|
||||
|
||||
if (stat(path, &info) < 0) {
|
||||
log_sys_very_verbose("stat", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!S_ISREG(info.st_mode)) {
|
||||
log_debug("%s: Not a regular file", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_insert_dev(path, 0)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _insert(const char *path, int rec)
|
||||
{
|
||||
struct stat info;
|
||||
@@ -355,19 +412,21 @@ static int _insert(const char *path, int rec)
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _full_scan(void)
|
||||
static void _full_scan(int dev_scan)
|
||||
{
|
||||
struct list *dh;
|
||||
struct dir_list *dl;
|
||||
|
||||
if (_cache.has_scanned)
|
||||
if (_cache.has_scanned && !dev_scan)
|
||||
return;
|
||||
|
||||
list_iterate(dh, &_cache.dirs) {
|
||||
struct dir_list *dl = list_item(dh, struct dir_list);
|
||||
list_iterate_items(dl, &_cache.dirs)
|
||||
_insert_dir(dl->dir);
|
||||
};
|
||||
|
||||
list_iterate_items(dl, &_cache.files)
|
||||
_insert_file(dl->dir);
|
||||
|
||||
_cache.has_scanned = 1;
|
||||
init_full_scan_done(1);
|
||||
}
|
||||
|
||||
int dev_cache_has_scanned(void)
|
||||
@@ -379,15 +438,14 @@ void dev_cache_scan(int do_scan)
|
||||
{
|
||||
if (!do_scan)
|
||||
_cache.has_scanned = 1;
|
||||
else {
|
||||
_cache.has_scanned = 0;
|
||||
_full_scan();
|
||||
}
|
||||
else
|
||||
_full_scan(1);
|
||||
}
|
||||
|
||||
int dev_cache_init(void)
|
||||
{
|
||||
_cache.names = NULL;
|
||||
_cache.has_scanned = 0;
|
||||
|
||||
if (!(_cache.mem = pool_create("dev_cache", 10 * 1024))) {
|
||||
stack;
|
||||
@@ -407,6 +465,7 @@ int dev_cache_init(void)
|
||||
}
|
||||
|
||||
list_init(&_cache.dirs);
|
||||
list_init(&_cache.files);
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -444,6 +503,7 @@ void dev_cache_exit(void)
|
||||
_cache.devices = NULL;
|
||||
_cache.has_scanned = 0;
|
||||
list_init(&_cache.dirs);
|
||||
list_init(&_cache.files);
|
||||
}
|
||||
|
||||
int dev_cache_add_dir(const char *path)
|
||||
@@ -472,6 +532,32 @@ int dev_cache_add_dir(const char *path)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dev_cache_add_loopfile(const char *path)
|
||||
{
|
||||
struct dir_list *dl;
|
||||
struct stat st;
|
||||
|
||||
if (stat(path, &st)) {
|
||||
log_error("Ignoring %s: %s", path, strerror(errno));
|
||||
/* But don't fail */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!S_ISREG(st.st_mode)) {
|
||||
log_error("Ignoring %s: Not a regular file", path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
|
||||
log_error("dir_list allocation failed for file");
|
||||
return 0;
|
||||
}
|
||||
|
||||
strcpy(dl->dir, path);
|
||||
list_add(&_cache.files, &dl->list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check cached device name is still valid before returning it */
|
||||
/* This should be a rare occurrence */
|
||||
/* set quiet if the cache is expected to be out-of-date */
|
||||
@@ -482,6 +568,9 @@ const char *dev_name_confirmed(struct device *dev, int quiet)
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
if ((dev->flags & DEV_REGULAR))
|
||||
return dev_name(dev);
|
||||
|
||||
while ((r = stat(name = list_item(dev->aliases.n,
|
||||
struct str_list)->str, &buf)) ||
|
||||
(buf.st_rdev != dev->dev)) {
|
||||
@@ -526,6 +615,9 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
|
||||
struct stat buf;
|
||||
struct device *d = (struct device *) hash_lookup(_cache.names, name);
|
||||
|
||||
if (d && (d->flags & DEV_REGULAR))
|
||||
return d;
|
||||
|
||||
/* If the entry's wrong, remove it */
|
||||
if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) {
|
||||
hash_remove(_cache.names, name);
|
||||
@@ -537,10 +629,11 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
|
||||
d = (struct device *) hash_lookup(_cache.names, name);
|
||||
}
|
||||
|
||||
return (d && (!f || f->passes_filter(f, d))) ? d : NULL;
|
||||
return (d && (!f || (d->flags & DEV_REGULAR) ||
|
||||
f->passes_filter(f, d))) ? d : NULL;
|
||||
}
|
||||
|
||||
struct dev_iter *dev_iter_create(struct dev_filter *f)
|
||||
struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
|
||||
{
|
||||
struct dev_iter *di = dbg_malloc(sizeof(*di));
|
||||
|
||||
@@ -549,7 +642,14 @@ struct dev_iter *dev_iter_create(struct dev_filter *f)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_full_scan();
|
||||
|
||||
if (dev_scan) {
|
||||
/* Flag gets reset between each command */
|
||||
if (!full_scan_done())
|
||||
persistent_filter_wipe(f); /* Calls _full_scan(1) */
|
||||
} else
|
||||
_full_scan(0);
|
||||
|
||||
di->current = btree_first(_cache.devices);
|
||||
di->filter = f;
|
||||
|
||||
@@ -572,7 +672,7 @@ struct device *dev_iter_get(struct dev_iter *iter)
|
||||
{
|
||||
while (iter->current) {
|
||||
struct device *d = _iter_next(iter);
|
||||
if (!iter->filter ||
|
||||
if (!iter->filter || (d->flags & DEV_REGULAR) ||
|
||||
iter->filter->passes_filter(iter->filter, d))
|
||||
return d;
|
||||
}
|
||||
|
||||
@@ -39,13 +39,14 @@ void dev_cache_scan(int do_scan);
|
||||
int dev_cache_has_scanned(void);
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
* Object for iterating through the cache.
|
||||
*/
|
||||
struct dev_iter;
|
||||
struct dev_iter *dev_iter_create(struct dev_filter *f);
|
||||
struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan);
|
||||
void dev_iter_destroy(struct dev_iter *iter);
|
||||
struct device *dev_iter_get(struct dev_iter *iter);
|
||||
|
||||
|
||||
@@ -222,11 +222,25 @@ static int _aligned_io(struct device_area *where, void *buffer,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
* Public functions
|
||||
*---------------------------------------------------------------*/
|
||||
static int _dev_get_size_file(const struct device *dev, uint64_t *size)
|
||||
{
|
||||
const char *name = dev_name(dev);
|
||||
struct stat info;
|
||||
|
||||
int dev_get_size(const struct device *dev, uint64_t *size)
|
||||
if (stat(name, &info)) {
|
||||
log_sys_error("stat", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*size = info.st_size;
|
||||
*size >>= SECTOR_SHIFT; /* Convert to sectors */
|
||||
|
||||
log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _dev_get_size_dev(const struct device *dev, uint64_t *size)
|
||||
{
|
||||
int fd;
|
||||
const char *name = dev_name(dev);
|
||||
@@ -252,6 +266,18 @@ int dev_get_size(const struct device *dev, uint64_t *size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
* Public functions
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
int dev_get_size(const struct device *dev, uint64_t *size)
|
||||
{
|
||||
if ((dev->flags & DEV_REGULAR))
|
||||
return _dev_get_size_file(dev, size);
|
||||
else
|
||||
return _dev_get_size_dev(dev, size);
|
||||
}
|
||||
|
||||
/* FIXME Unused
|
||||
int dev_get_sectsize(struct device *dev, uint32_t *size)
|
||||
{
|
||||
@@ -330,8 +356,13 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
|
||||
}
|
||||
|
||||
#ifdef O_DIRECT_SUPPORT
|
||||
if (direct)
|
||||
flags |= O_DIRECT;
|
||||
if (direct) {
|
||||
if (!(dev->flags & DEV_O_DIRECT_TESTED))
|
||||
dev->flags |= DEV_O_DIRECT;
|
||||
|
||||
if ((dev->flags & DEV_O_DIRECT))
|
||||
flags |= O_DIRECT;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef O_NOATIME
|
||||
@@ -341,12 +372,31 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
|
||||
#endif
|
||||
|
||||
if ((dev->fd = open(name, flags, 0777)) < 0) {
|
||||
log_sys_error("open", name);
|
||||
#ifdef O_DIRECT_SUPPORT
|
||||
if (direct && !(dev->flags & DEV_O_DIRECT_TESTED)) {
|
||||
flags &= ~O_DIRECT;
|
||||
if ((dev->fd = open(name, flags, 0777)) >= 0) {
|
||||
dev->flags &= ~DEV_O_DIRECT;
|
||||
log_debug("%s: Not using O_DIRECT", name);
|
||||
goto opened;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (quiet)
|
||||
log_sys_debug("open", name);
|
||||
else
|
||||
log_sys_error("open", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef O_DIRECT_SUPPORT
|
||||
opened:
|
||||
if (direct)
|
||||
dev->flags |= DEV_O_DIRECT_TESTED;
|
||||
#endif
|
||||
dev->open_count++;
|
||||
dev->flags &= ~DEV_ACCESSED_W;
|
||||
|
||||
if ((flags & O_ACCMODE) == O_RDWR)
|
||||
dev->flags |= DEV_OPENED_RW;
|
||||
else
|
||||
@@ -370,8 +420,9 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
|
||||
|
||||
list_add(&_open_devices, &dev->open_list);
|
||||
|
||||
log_debug("Opened %s %s", dev_name(dev),
|
||||
dev->flags & DEV_OPENED_RW ? "RW" : "RO");
|
||||
log_debug("Opened %s %s%s", dev_name(dev),
|
||||
dev->flags & DEV_OPENED_RW ? "RW" : "RO",
|
||||
dev->flags & DEV_O_DIRECT ? " O_DIRECT" : "");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#define DEV_REGULAR 0x00000002 /* Regular file? */
|
||||
#define DEV_ALLOCED 0x00000004 /* dbg_malloc used */
|
||||
#define DEV_OPENED_RW 0x00000008 /* Opened RW */
|
||||
#define DEV_O_DIRECT 0x00000010 /* Use O_DIRECT */
|
||||
#define DEV_O_DIRECT_TESTED 0x00000020 /* DEV_O_DIRECT is reliable */
|
||||
|
||||
/*
|
||||
* All devices in LVM will be represented by one of these.
|
||||
@@ -41,6 +43,7 @@ struct device {
|
||||
struct list open_list;
|
||||
|
||||
char pvid[ID_LEN + 1];
|
||||
char _padding[7];
|
||||
};
|
||||
|
||||
struct device_list {
|
||||
@@ -63,7 +66,7 @@ int dev_get_sectsize(struct device *dev, uint32_t *size);
|
||||
/* Use quiet version if device number could change e.g. when opening LV */
|
||||
int dev_open(struct device *dev);
|
||||
int dev_open_quiet(struct device *dev);
|
||||
int dev_open_flags(struct device *dev, int flags, int append, int quiet);
|
||||
int dev_open_flags(struct device *dev, int flags, int direct, int quiet);
|
||||
int dev_close(struct device *dev);
|
||||
int dev_close_immediate(struct device *dev);
|
||||
void dev_close_all(void);
|
||||
@@ -80,7 +83,7 @@ int dev_zero(struct device *dev, uint64_t offset, size_t len);
|
||||
void dev_flush(struct device *dev);
|
||||
|
||||
struct device *dev_create_file(const char *filename, struct device *dev,
|
||||
struct str_list *alias);
|
||||
struct str_list *alias, int use_malloc);
|
||||
|
||||
static inline const char *dev_name(const struct device *dev)
|
||||
{
|
||||
|
||||
@@ -258,7 +258,7 @@ void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
|
||||
size,
|
||||
display_size(cmd, (pv->size -
|
||||
pv->pe_count * pv->pe_size),
|
||||
(uint64_t) pv->pe_count * pv->pe_size),
|
||||
SIZE_SHORT));
|
||||
|
||||
} else
|
||||
@@ -337,10 +337,9 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle)
|
||||
{
|
||||
struct lvinfo info;
|
||||
int inkernel, snap_active;
|
||||
int inkernel, snap_active = 0;
|
||||
char uuid[64];
|
||||
struct snapshot *snap = NULL;
|
||||
struct list *slh, *snaplist;
|
||||
struct lv_segment *snap_seg = NULL;
|
||||
float snap_percent; /* fused, fsize; */
|
||||
|
||||
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
|
||||
@@ -364,27 +363,30 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (lv_is_origin(lv)) {
|
||||
log_print("LV snapshot status source of");
|
||||
|
||||
snaplist = find_snapshots(lv);
|
||||
list_iterate(slh, snaplist) {
|
||||
snap = list_item(slh, struct snapshot_list)->snapshot;
|
||||
snap_active = lv_snapshot_percent(snap->cow,
|
||||
&snap_percent);
|
||||
if (!snap_active || snap_percent < 0 ||
|
||||
snap_percent >= 100) snap_active = 0;
|
||||
list_iterate_items_gen(snap_seg, &lv->snapshot_segs,
|
||||
origin_list) {
|
||||
if (inkernel &&
|
||||
(snap_active = lv_snapshot_percent(snap_seg->cow,
|
||||
&snap_percent)))
|
||||
if (snap_percent < 0 || snap_percent >= 100)
|
||||
snap_active = 0;
|
||||
log_print(" %s%s/%s [%s]",
|
||||
lv->vg->cmd->dev_dir, lv->vg->name,
|
||||
snap->cow->name,
|
||||
snap_seg->cow->name,
|
||||
(snap_active > 0) ? "active" : "INACTIVE");
|
||||
}
|
||||
snap = NULL;
|
||||
} else if ((snap = find_cow(lv))) {
|
||||
snap_active = lv_snapshot_percent(lv, &snap_percent);
|
||||
if (!snap_active || snap_percent < 0 || snap_percent >= 100)
|
||||
snap_active = 0;
|
||||
snap_seg = NULL;
|
||||
} else if ((snap_seg = find_cow(lv))) {
|
||||
if (inkernel &&
|
||||
(snap_active = lv_snapshot_percent(snap_seg->cow,
|
||||
&snap_percent)))
|
||||
if (snap_percent < 0 || snap_percent >= 100)
|
||||
snap_active = 0;
|
||||
|
||||
log_print("LV snapshot status %s destination for %s%s/%s",
|
||||
(snap_active > 0) ? "active" : "INACTIVE",
|
||||
lv->vg->cmd->dev_dir, lv->vg->name,
|
||||
snap->origin->name);
|
||||
snap_seg->origin->name);
|
||||
}
|
||||
|
||||
if (inkernel && info.suspended)
|
||||
@@ -402,15 +404,24 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
|
||||
log_print("LV Size %s",
|
||||
display_size(cmd,
|
||||
snap ? snap->origin->size : lv->size,
|
||||
snap_seg ? snap_seg->origin->size : lv->size,
|
||||
SIZE_SHORT));
|
||||
|
||||
log_print("Current LE %u",
|
||||
snap ? snap->origin->le_count : lv->le_count);
|
||||
snap_seg ? snap_seg->origin->le_count : lv->le_count);
|
||||
|
||||
/********** FIXME allocation
|
||||
log_print("Allocated LE %u", lv->allocated_le);
|
||||
**********/
|
||||
if (snap_seg) {
|
||||
log_print("COW-table size %s",
|
||||
display_size(cmd, (uint64_t) lv->size, SIZE_SHORT));
|
||||
log_print("COW-table LE %u", lv->le_count);
|
||||
|
||||
if (snap_active)
|
||||
log_print("Allocated to snapshot %.2f%% ", snap_percent);
|
||||
|
||||
log_print("Snapshot chunk size %s",
|
||||
display_size(cmd, (uint64_t) snap_seg->chunk_size,
|
||||
SIZE_SHORT));
|
||||
}
|
||||
|
||||
log_print("Segments %u", list_size(&lv->segments));
|
||||
|
||||
@@ -418,31 +429,6 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
log_print("Stripe size (KByte) %u", lv->stripesize / 2);
|
||||
***********/
|
||||
|
||||
if (snap) {
|
||||
if (snap_percent == -1)
|
||||
snap_percent = 100;
|
||||
|
||||
log_print("Snapshot chunk size %s",
|
||||
display_size(cmd, (uint64_t) snap->chunk_size,
|
||||
SIZE_SHORT));
|
||||
|
||||
/*
|
||||
size = display_size(lv->size, SIZE_SHORT);
|
||||
sscanf(size, "%f", &fsize);
|
||||
fused = fsize * snap_percent / 100;
|
||||
*/
|
||||
log_print("Allocated to snapshot %.2f%% ", /* [%.2f/%s]", */
|
||||
snap_percent); /*, fused, size); */
|
||||
/* dbg_free(size); */
|
||||
}
|
||||
|
||||
/********** FIXME Snapshot
|
||||
size = ???
|
||||
log_print("Allocated to COW-table %s", size);
|
||||
dbg_free(size);
|
||||
}
|
||||
******************/
|
||||
|
||||
log_print("Allocation %s", get_alloc_string(lv->alloc));
|
||||
log_print("Read ahead sectors %u", lv->read_ahead);
|
||||
|
||||
@@ -463,26 +449,28 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
|
||||
void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre)
|
||||
{
|
||||
switch (seg->area[s].type) {
|
||||
switch (seg_type(seg, s)) {
|
||||
case AREA_PV:
|
||||
/* FIXME Re-check the conditions for 'Missing' */
|
||||
log_print("%sPhysical volume\t%s", pre,
|
||||
seg->area[s].u.pv.pv ?
|
||||
dev_name(seg->area[s].u.pv.pv->dev) : "Missing");
|
||||
seg_pv(seg, s) ?
|
||||
dev_name(seg_dev(seg, s)) :
|
||||
"Missing");
|
||||
|
||||
if (seg->area[s].u.pv.pv)
|
||||
if (seg_pv(seg, s))
|
||||
log_print("%sPhysical extents\t%d to %d", pre,
|
||||
seg->area[s].u.pv.pe,
|
||||
seg->area[s].u.pv.pe + seg->area_len - 1);
|
||||
seg_pe(seg, s),
|
||||
seg_pe(seg, s) + seg->area_len - 1);
|
||||
break;
|
||||
case AREA_LV:
|
||||
log_print("%sLogical volume\t%s", pre,
|
||||
seg->area[s].u.lv.lv ?
|
||||
seg->area[s].u.lv.lv->name : "Missing");
|
||||
seg_lv(seg, s) ?
|
||||
seg_lv(seg, s)->name : "Missing");
|
||||
|
||||
if (seg->area[s].u.lv.lv)
|
||||
if (seg_lv(seg, s))
|
||||
log_print("%sLogical extents\t%d to %d", pre,
|
||||
seg->area[s].u.lv.le,
|
||||
seg->area[s].u.lv.le + seg->area_len - 1);
|
||||
seg_le(seg, s),
|
||||
seg_le(seg, s) + seg->area_len - 1);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -550,7 +538,7 @@ void vgdisplay_full(struct volume_group *vg)
|
||||
vg->status & SHARED ? "yes" : "no");
|
||||
}
|
||||
log_print("MAX LV %u", vg->max_lv);
|
||||
log_print("Cur LV %u", vg->lv_count);
|
||||
log_print("Cur LV %u", vg->lv_count + vg->snapshot_count);
|
||||
log_print("Open LV %u", lvs_in_vg_opened(vg));
|
||||
/****** FIXME Max LV Size
|
||||
log_print ( "MAX LV Size %s",
|
||||
|
||||
@@ -53,7 +53,9 @@ int persistent_filter_wipe(struct dev_filter *f)
|
||||
{
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
|
||||
log_verbose("Wiping cache of LVM-capable devices");
|
||||
hash_wipe(pf->devices);
|
||||
|
||||
/* Trigger complete device scan */
|
||||
dev_cache_scan(1);
|
||||
|
||||
@@ -202,16 +204,14 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
void *l = hash_lookup(pf->devices, dev_name(dev));
|
||||
struct str_list *sl;
|
||||
struct list *ah;
|
||||
|
||||
if (!l) {
|
||||
l = pf->real->passes_filter(pf->real, dev) ?
|
||||
PF_GOOD_DEVICE : PF_BAD_DEVICE;
|
||||
|
||||
list_iterate(ah, &dev->aliases) {
|
||||
sl = list_item(ah, struct str_list);
|
||||
list_iterate_items(sl, &dev->aliases)
|
||||
hash_insert(pf->devices, sl->str, l);
|
||||
}
|
||||
|
||||
} else if (l == PF_BAD_DEVICE)
|
||||
log_debug("%s: Skipping (cached)", dev_name(dev));
|
||||
|
||||
|
||||
@@ -158,13 +158,11 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
|
||||
static int _accept_p(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
struct list *ah;
|
||||
int m, first = 1, rejected = 0;
|
||||
struct rfilter *rf = (struct rfilter *) f->private;
|
||||
struct str_list *sl;
|
||||
|
||||
list_iterate(ah, &dev->aliases) {
|
||||
sl = list_item(ah, struct str_list);
|
||||
list_iterate_items(sl, &dev->aliases) {
|
||||
m = matcher_run(rf->engine, sl->str);
|
||||
|
||||
if (m >= 0) {
|
||||
|
||||
@@ -172,7 +172,7 @@ static int _read_devs(struct dev_set *ds, const char *dir)
|
||||
unsigned char dtype;
|
||||
struct stat info;
|
||||
char path[PATH_MAX];
|
||||
dev_t dev;
|
||||
dev_t dev = { 0 };
|
||||
int r = 1;
|
||||
|
||||
if (!(dr = opendir(dir))) {
|
||||
|
||||
@@ -69,6 +69,8 @@ static const device_info_t device_info[] = {
|
||||
{"power2", 16}, /* EMC Powerpath */
|
||||
{"i2o_block", 16}, /* i2o Block Disk */
|
||||
{"iseries/vd", 8}, /* iSeries disks */
|
||||
{"gnbd", 1}, /* Network block device */
|
||||
{"ramdisk", 1}, /* RAM disk */
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
@@ -87,7 +89,7 @@ static int _passes_lvm_type_device_filter(struct dev_filter *f,
|
||||
}
|
||||
|
||||
/* Check it's accessible */
|
||||
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
|
||||
if (!dev_open_flags(dev, O_RDONLY, 0, 1)) {
|
||||
log_debug("%s: Skipping: open failed", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -424,11 +424,11 @@ struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
|
||||
|
||||
static void _add_pv_to_list(struct list *head, struct disk_list *data)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct pv_disk *pvd;
|
||||
struct disk_list *diskl;
|
||||
|
||||
list_iterate(pvdh, head) {
|
||||
pvd = &list_item(pvdh, struct disk_list)->pvd;
|
||||
list_iterate_items(diskl, head) {
|
||||
pvd = &diskl->pvd;
|
||||
if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
|
||||
sizeof(pvd->pv_uuid))) {
|
||||
if (MAJOR(data->dev->dev) != md_major()) {
|
||||
@@ -439,7 +439,7 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
|
||||
}
|
||||
log_very_verbose("Duplicate PV %s - using md %s",
|
||||
pvd->pv_uuid, dev_name(data->dev));
|
||||
list_del(pvdh);
|
||||
list_del(&diskl->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -458,14 +458,14 @@ int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
struct disk_list *data = NULL;
|
||||
struct list *vgih;
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_info *info;
|
||||
|
||||
/* Fast path if we already saw this VG and cached the list of PVs */
|
||||
if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
|
||||
vginfo->infos.n) {
|
||||
list_iterate(vgih, &vginfo->infos) {
|
||||
dev = list_item(vgih, struct lvmcache_info)->dev;
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
dev = info->dev;
|
||||
if (dev && !(data = read_disk(fmt, dev, mem, vg_name)))
|
||||
break;
|
||||
_add_pv_to_list(head, data);
|
||||
@@ -482,7 +482,7 @@ int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
|
||||
/* vgcache_del(vg_name); */
|
||||
}
|
||||
|
||||
if (!(iter = dev_iter_create(filter))) {
|
||||
if (!(iter = dev_iter_create(filter, 1))) {
|
||||
log_error("read_pvs_in_vg: dev_iter_create failed");
|
||||
return 0;
|
||||
}
|
||||
@@ -518,18 +518,16 @@ static int _write_vgd(struct disk_list *data)
|
||||
static int _write_uuids(struct disk_list *data)
|
||||
{
|
||||
struct uuid_list *ul;
|
||||
struct list *uh;
|
||||
uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
|
||||
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
|
||||
|
||||
list_iterate(uh, &data->uuids) {
|
||||
list_iterate_items(ul, &data->uuids) {
|
||||
if (pos >= end) {
|
||||
log_error("Too many uuids to fit on %s",
|
||||
dev_name(data->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ul = list_item(uh, struct uuid_list);
|
||||
if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid))
|
||||
fail;
|
||||
|
||||
@@ -552,7 +550,7 @@ static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
|
||||
|
||||
static int _write_lvs(struct disk_list *data)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct lvd_list *ll;
|
||||
uint64_t pos, offset;
|
||||
|
||||
pos = data->pvd.lv_on_disk.base;
|
||||
@@ -563,9 +561,7 @@ static int _write_lvs(struct disk_list *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(lvh, &data->lvds) {
|
||||
struct lvd_list *ll = list_item(lvh, struct lvd_list);
|
||||
|
||||
list_iterate_items(ll, &data->lvds) {
|
||||
offset = sizeof(struct lv_disk) * ll->lvd.lv_number;
|
||||
if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) {
|
||||
log_error("lv_number %d too large", ll->lvd.lv_number);
|
||||
@@ -704,11 +700,9 @@ static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data)
|
||||
*/
|
||||
int write_disks(const struct format_type *fmt, struct list *pvs)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct disk_list *dl;
|
||||
|
||||
list_iterate(pvh, pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
list_iterate_items(dl, pvs) {
|
||||
if (!(_write_all_pvd(fmt, dl)))
|
||||
fail;
|
||||
|
||||
|
||||
@@ -46,9 +46,7 @@ static int _check_vgs(struct list *pvs, int *partial)
|
||||
* This means an active VG won't be affected if disks are inserted
|
||||
* bearing an exported VG with the same name.
|
||||
*/
|
||||
list_iterate(pvh, pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
|
||||
list_iterate_items(dl, pvs) {
|
||||
if (first_time) {
|
||||
exported = dl->pvd.pv_status & VG_EXPORTED;
|
||||
first_time = 0;
|
||||
@@ -148,7 +146,6 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
||||
vg->seqno = 0;
|
||||
list_init(&vg->pvs);
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
list_init(&vg->tags);
|
||||
|
||||
if (!_check_vgs(pvs, &partial))
|
||||
@@ -247,13 +244,10 @@ static int _flatten_vg(struct format_instance *fid, struct pool *mem,
|
||||
struct list *pvds, const char *dev_dir,
|
||||
struct dev_filter *filter)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
struct disk_list *data;
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (!(data = _flatten_pv(fid, mem, vg, pvl->pv, dev_dir))) {
|
||||
stack;
|
||||
return 0;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "filter.h"
|
||||
#include "toolcontext.h"
|
||||
#include "segtype.h"
|
||||
#include "pv_alloc.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
@@ -86,9 +87,15 @@ int import_pv(struct pool *mem, struct device *dev,
|
||||
pv->pe_size = pvd->pe_size;
|
||||
pv->pe_start = pvd->pe_start;
|
||||
pv->pe_count = pvd->pe_total;
|
||||
pv->pe_alloc_count = pvd->pe_allocated;
|
||||
pv->pe_alloc_count = 0;
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
|
||||
if (!alloc_pv_segment_whole_pv(mem, pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -323,6 +330,8 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
|
||||
lv->size = lvd->lv_size;
|
||||
lv->le_count = lvd->lv_allocated_le;
|
||||
|
||||
lv->snapshot = NULL;
|
||||
list_init(&lv->snapshot_segs);
|
||||
list_init(&lv->segments);
|
||||
list_init(&lv->tags);
|
||||
|
||||
@@ -373,14 +382,11 @@ static void _export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
||||
int export_extents(struct disk_list *dl, uint32_t lv_num,
|
||||
struct logical_volume *lv, struct physical_volume *pv)
|
||||
{
|
||||
struct list *segh;
|
||||
struct pe_disk *ped;
|
||||
struct lv_segment *seg;
|
||||
uint32_t pe, s;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) {
|
||||
log_error("Segment type %s in LV %s: "
|
||||
@@ -388,16 +394,16 @@ int export_extents(struct disk_list *dl, uint32_t lv_num,
|
||||
seg->segtype->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
if (seg->area[s].type != AREA_PV) {
|
||||
if (seg_type(seg, s) != AREA_PV) {
|
||||
log_error("LV stripe found in LV %s: "
|
||||
"unsupported by format1", lv->name);
|
||||
return 0;
|
||||
}
|
||||
if (seg->area[s].u.pv.pv != pv)
|
||||
if (seg_pv(seg, s) != pv)
|
||||
continue; /* not our pv */
|
||||
|
||||
for (pe = 0; pe < (seg->len / seg->area_count); pe++) {
|
||||
ped = &dl->extents[pe + seg->area[s].u.pv.pe];
|
||||
ped = &dl->extents[pe + seg_pe(seg, s)];
|
||||
ped->lv_num = lv_num;
|
||||
ped->le_num = (seg->le / seg->area_count) + pe +
|
||||
s * (lv->le_count / seg->area_count);
|
||||
@@ -412,15 +418,11 @@ int import_pvs(const struct format_type *fmt, struct pool *mem,
|
||||
struct volume_group *vg,
|
||||
struct list *pvds, struct list *results, int *count)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct disk_list *dl;
|
||||
struct pv_list *pvl;
|
||||
|
||||
*count = 0;
|
||||
list_iterate(pvdh, pvds) {
|
||||
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
|
||||
list_iterate_items(dl, pvds) {
|
||||
if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
|
||||
!(pvl->pv = pool_alloc(mem, sizeof(*pvl->pv)))) {
|
||||
stack;
|
||||
@@ -471,12 +473,9 @@ int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds)
|
||||
struct disk_list *dl;
|
||||
struct lvd_list *ll;
|
||||
struct lv_disk *lvd;
|
||||
struct list *pvdh, *lvdh;
|
||||
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
list_iterate(lvdh, &dl->lvds) {
|
||||
ll = list_item(lvdh, struct lvd_list);
|
||||
list_iterate_items(dl, pvds) {
|
||||
list_iterate_items(ll, &dl->lvds) {
|
||||
lvd = &ll->lvd;
|
||||
|
||||
if (!find_lv(vg, lvd->lv_name) &&
|
||||
@@ -495,7 +494,6 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
struct physical_volume *pv, const char *dev_dir)
|
||||
{
|
||||
int r = 0;
|
||||
struct list *lvh, *sh;
|
||||
struct lv_list *ll;
|
||||
struct lvd_list *lvdl;
|
||||
size_t len;
|
||||
@@ -522,8 +520,10 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
}
|
||||
memset(dl->extents, 0, len);
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
ll = list_item(lvh, struct lv_list);
|
||||
list_iterate_items(ll, &vg->lvs) {
|
||||
if (ll->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
|
||||
stack;
|
||||
goto out;
|
||||
@@ -532,7 +532,6 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
_export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
|
||||
|
||||
lv_num = lvnum_from_lvid(&ll->lv->lvid);
|
||||
|
||||
lvdl->lvd.lv_number = lv_num;
|
||||
|
||||
if (!hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd)) {
|
||||
@@ -545,37 +544,20 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lv_is_origin(ll->lv))
|
||||
lvdl->lvd.lv_access |= LV_SNAPSHOT_ORG;
|
||||
|
||||
if (lv_is_cow(ll->lv)) {
|
||||
lvdl->lvd.lv_access |= LV_SNAPSHOT;
|
||||
lvdl->lvd.lv_chunk_size = ll->lv->snapshot->chunk_size;
|
||||
lvdl->lvd.lv_snapshot_minor =
|
||||
lvnum_from_lvid(&ll->lv->snapshot->origin->lvid);
|
||||
}
|
||||
|
||||
list_add(&dl->lvds, &lvdl->list);
|
||||
dl->pvd.lv_cur++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we need to run through the snapshots, exporting
|
||||
* the SNAPSHOT_ORG flags etc.
|
||||
*/
|
||||
list_iterate(sh, &vg->snapshots) {
|
||||
struct lv_disk *org, *cow;
|
||||
struct snapshot *s = list_item(sh,
|
||||
struct snapshot_list)->snapshot;
|
||||
|
||||
if (!(org = hash_lookup(lvd_hash, s->origin->name))) {
|
||||
log_err("Couldn't find snapshot origin '%s'.",
|
||||
s->origin->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(cow = hash_lookup(lvd_hash, s->cow->name))) {
|
||||
log_err("Couldn't find snapshot cow store '%s'.",
|
||||
s->cow->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
org->lv_access |= LV_SNAPSHOT_ORG;
|
||||
cow->lv_access |= LV_SNAPSHOT;
|
||||
cow->lv_snapshot_minor = org->lv_number;
|
||||
cow->lv_chunk_size = s->chunk_size;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
@@ -590,19 +572,17 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
|
||||
struct list *pvds)
|
||||
{
|
||||
struct logical_volume *lvs[MAX_LV];
|
||||
struct list *pvdh, *lvdh;
|
||||
struct disk_list *dl;
|
||||
struct lvd_list *ll;
|
||||
struct lv_disk *lvd;
|
||||
int lvnum;
|
||||
struct logical_volume *org, *cow;
|
||||
|
||||
/* build an index of lv numbers */
|
||||
memset(lvs, 0, sizeof(lvs));
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
|
||||
list_iterate(lvdh, &dl->lvds) {
|
||||
lvd = &(list_item(lvdh, struct lvd_list)->lvd);
|
||||
list_iterate_items(dl, pvds) {
|
||||
list_iterate_items(ll, &dl->lvds) {
|
||||
lvd = &ll->lvd;
|
||||
|
||||
lvnum = lvd->lv_number;
|
||||
|
||||
@@ -624,11 +604,9 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
|
||||
/*
|
||||
* Now iterate through yet again adding the snapshots.
|
||||
*/
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
|
||||
list_iterate(lvdh, &dl->lvds) {
|
||||
lvd = &(list_item(lvdh, struct lvd_list)->lvd);
|
||||
list_iterate_items(dl, pvds) {
|
||||
list_iterate_items(ll, &dl->lvds) {
|
||||
lvd = &ll->lvd;
|
||||
|
||||
if (!(lvd->lv_access & LV_SNAPSHOT))
|
||||
continue;
|
||||
@@ -646,7 +624,8 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
|
||||
continue;
|
||||
|
||||
/* insert the snapshot */
|
||||
if (!vg_add_snapshot(org, cow, 1, NULL,
|
||||
if (!vg_add_snapshot(vg->fid, NULL, org, cow, NULL,
|
||||
org->le_count,
|
||||
lvd->lv_chunk_size)) {
|
||||
log_err("Couldn't add snapshot.");
|
||||
return 0;
|
||||
@@ -661,10 +640,8 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg)
|
||||
{
|
||||
struct uuid_list *ul;
|
||||
struct pv_list *pvl;
|
||||
struct list *pvh;
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (!(ul = pool_alloc(dl->mem, sizeof(*ul)))) {
|
||||
stack;
|
||||
return 0;
|
||||
@@ -684,14 +661,11 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg)
|
||||
*/
|
||||
void export_numbers(struct list *pvds, struct volume_group *vg)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct disk_list *dl;
|
||||
int pv_num = 1;
|
||||
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
list_iterate_items(dl, pvds)
|
||||
dl->pvd.pv_number = pv_num++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -699,26 +673,20 @@ void export_numbers(struct list *pvds, struct volume_group *vg)
|
||||
*/
|
||||
void export_pv_act(struct list *pvds)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct disk_list *dl;
|
||||
int act = 0;
|
||||
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
list_iterate_items(dl, pvds)
|
||||
if (dl->pvd.pv_status & PV_ACTIVE)
|
||||
act++;
|
||||
}
|
||||
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
list_iterate_items(dl, pvds)
|
||||
dl->vgd.pv_act = act;
|
||||
}
|
||||
}
|
||||
|
||||
int export_vg_number(struct format_instance *fid, struct list *pvds,
|
||||
const char *vg_name, struct dev_filter *filter)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct disk_list *dl;
|
||||
int vg_num;
|
||||
|
||||
@@ -727,10 +695,8 @@ int export_vg_number(struct format_instance *fid, struct list *pvds,
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
list_iterate_items(dl, pvds)
|
||||
dl->vgd.vg_number = vg_num;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ static struct hash_table *_create_lv_maps(struct pool *mem,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
struct hash_table *maps = hash_create(32);
|
||||
struct list *llh;
|
||||
struct lv_list *ll;
|
||||
struct lv_map *lvm;
|
||||
|
||||
@@ -58,8 +57,9 @@ static struct hash_table *_create_lv_maps(struct pool *mem,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate(llh, &vg->lvs) {
|
||||
ll = list_item(llh, struct lv_list);
|
||||
list_iterate_items(ll, &vg->lvs) {
|
||||
if (ll->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
if (!(lvm = pool_alloc(mem, sizeof(*lvm)))) {
|
||||
stack;
|
||||
@@ -89,13 +89,12 @@ static struct hash_table *_create_lv_maps(struct pool *mem,
|
||||
static int _fill_lv_array(struct lv_map **lvs,
|
||||
struct hash_table *maps, struct disk_list *dl)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct lvd_list *ll;
|
||||
struct lv_map *lvm;
|
||||
|
||||
memset(lvs, 0, sizeof(*lvs) * MAX_LV);
|
||||
list_iterate(lvh, &dl->lvds) {
|
||||
struct lvd_list *ll = list_item(lvh, struct lvd_list);
|
||||
|
||||
list_iterate_items(ll, &dl->lvds) {
|
||||
if (!(lvm = hash_lookup(maps, strrchr(ll->lvd.lv_name, '/')
|
||||
+ 1))) {
|
||||
log_err("Physical volume (%s) contains an "
|
||||
@@ -116,15 +115,13 @@ static int _fill_lv_array(struct lv_map **lvs,
|
||||
static int _fill_maps(struct hash_table *maps, struct volume_group *vg,
|
||||
struct list *pvds)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct disk_list *dl;
|
||||
struct physical_volume *pv;
|
||||
struct lv_map *lvms[MAX_LV], *lvm;
|
||||
struct pe_disk *e;
|
||||
uint32_t i, lv_num, le;
|
||||
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
list_iterate_items(dl, pvds) {
|
||||
pv = find_pv(vg, dl->dev);
|
||||
e = dl->extents;
|
||||
|
||||
@@ -205,58 +202,59 @@ static int _check_maps_are_complete(struct hash_table *maps)
|
||||
|
||||
static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
{
|
||||
uint32_t le = 0;
|
||||
uint32_t le = 0, len;
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (le < lvm->lv->le_count) {
|
||||
seg = alloc_lv_segment(cmd->mem, 1);
|
||||
len = 0;
|
||||
|
||||
seg->lv = lvm->lv;
|
||||
if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||
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));
|
||||
|
||||
if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le,
|
||||
len, 0, 0, NULL, 1, len, 0, 0, 0))) {
|
||||
log_error("Failed to allocate linear segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!set_lv_segment_area_pv(seg, 0, lvm->map[le].pv,
|
||||
lvm->map[le].pe)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->le = le;
|
||||
seg->len = 0;
|
||||
seg->area_len = 0;
|
||||
seg->stripe_size = 0;
|
||||
|
||||
seg->area[0].type = AREA_PV;
|
||||
seg->area[0].u.pv.pv = lvm->map[le].pv;
|
||||
seg->area[0].u.pv.pe = lvm->map[le].pe;
|
||||
|
||||
do {
|
||||
seg->len++;
|
||||
seg->area_len++;
|
||||
} while ((lvm->map[le + seg->len].pv == seg->area[0].u.pv.pv) &&
|
||||
(seg->area[0].u.pv.pv &&
|
||||
lvm->map[le + seg->len].pe == seg->area[0].u.pv.pe +
|
||||
seg->len));
|
||||
list_add(&lvm->lv->segments, &seg->list);
|
||||
|
||||
le += seg->len;
|
||||
|
||||
list_add(&lvm->lv->segments, &seg->list);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
|
||||
uint32_t base_le, uint32_t len)
|
||||
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 le, st;
|
||||
|
||||
le = base_le + seg->len;
|
||||
uint32_t st;
|
||||
|
||||
/*
|
||||
* Is the next physical extent in every stripe adjacent to the last?
|
||||
*/
|
||||
for (st = 0; st < seg->area_count; st++)
|
||||
if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) ||
|
||||
(seg->area[st].u.pv.pv &&
|
||||
lvm->map[le + st * len].pe !=
|
||||
seg->area[st].u.pv.pe + seg->len)) return 0;
|
||||
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))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -264,7 +262,9 @@ static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
|
||||
static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
{
|
||||
uint32_t st, le = 0, len;
|
||||
uint32_t area_len;
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
|
||||
/*
|
||||
* Work out overall striped length
|
||||
@@ -276,43 +276,46 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
}
|
||||
len = lvm->lv->le_count / lvm->stripes;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (le < len) {
|
||||
if (!(seg = alloc_lv_segment(cmd->mem, lvm->stripes))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->lv = lvm->lv;
|
||||
if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
seg->stripe_size = lvm->stripe_size;
|
||||
seg->le = seg->area_count * le;
|
||||
seg->len = 1;
|
||||
seg->area_len = 1;
|
||||
|
||||
/*
|
||||
* Set up start positions of each stripe in this segment
|
||||
*/
|
||||
for (st = 0; st < seg->area_count; st++) {
|
||||
seg->area[st].u.pv.pv = lvm->map[le + st * len].pv;
|
||||
seg->area[st].u.pv.pe = lvm->map[le + st * len].pe;
|
||||
}
|
||||
area_len = 1;
|
||||
|
||||
/*
|
||||
* Find how many blocks are contiguous in all stripes
|
||||
* and so can form part of this segment
|
||||
*/
|
||||
while (_check_stripe(lvm, seg, le, len)) {
|
||||
seg->len++;
|
||||
seg->area_len++;
|
||||
while (_check_stripe(lvm, lvm->stripes,
|
||||
area_len * lvm->stripes, le, len))
|
||||
area_len++;
|
||||
|
||||
if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv,
|
||||
lvm->stripes * le,
|
||||
lvm->stripes * area_len,
|
||||
0, lvm->stripe_size, NULL,
|
||||
lvm->stripes,
|
||||
area_len, 0, 0, 0))) {
|
||||
log_error("Failed to allocate striped segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
le += seg->len;
|
||||
seg->len *= seg->area_count;
|
||||
/*
|
||||
* Set up start positions of each stripe in this segment
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
list_add(&lvm->lv->segments, &seg->list);
|
||||
|
||||
le += seg->len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
||||
const char *candidate_vg, int *result)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct list all_pvs;
|
||||
struct disk_list *dl;
|
||||
struct pool *mem = pool_create("lvm1 vg_number", 10 * 1024);
|
||||
@@ -47,8 +46,7 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
||||
|
||||
memset(numbers, 0, sizeof(numbers));
|
||||
|
||||
list_iterate(pvh, &all_pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
list_iterate_items(dl, &all_pvs) {
|
||||
if (!*dl->pvd.vg_name || !strcmp(dl->pvd.vg_name, candidate_vg))
|
||||
continue;
|
||||
|
||||
|
||||
@@ -57,12 +57,9 @@ static int __read_pool_disk(const struct format_type *fmt, struct device *dev,
|
||||
|
||||
static void _add_pl_to_list(struct list *head, struct pool_list *data)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct pool_list *pl;
|
||||
|
||||
list_iterate(pvdh, head) {
|
||||
pl = list_item(pvdh, struct pool_list);
|
||||
|
||||
list_iterate_items(pl, head) {
|
||||
if (id_equal(&data->pv_uuid, &pl->pv_uuid)) {
|
||||
char uuid[ID_LEN + 7];
|
||||
|
||||
@@ -76,7 +73,7 @@ static void _add_pl_to_list(struct list *head, struct pool_list *data)
|
||||
}
|
||||
log_very_verbose("Duplicate PV %s - using md %s",
|
||||
uuid, dev_name(data->dev));
|
||||
list_del(pvdh);
|
||||
list_del(&pl->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -247,11 +244,9 @@ static int _read_vg_pds(const struct format_type *fmt, struct pool *mem,
|
||||
struct lvmcache_vginfo *vginfo, struct list *head,
|
||||
uint32_t *devcount)
|
||||
{
|
||||
|
||||
struct list *vgih = NULL;
|
||||
struct device *dev;
|
||||
struct pool_list *pl = NULL;
|
||||
struct pool *tmpmem = NULL;
|
||||
struct lvmcache_info *info;
|
||||
struct pool_list *pl;
|
||||
struct pool *tmpmem;
|
||||
|
||||
uint32_t sp_count = 0;
|
||||
uint32_t *sp_devs = NULL;
|
||||
@@ -264,16 +259,16 @@ static int _read_vg_pds(const struct format_type *fmt, struct pool *mem,
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(vgih, &vginfo->infos) {
|
||||
dev = list_item(vgih, struct lvmcache_info)->dev;
|
||||
if (dev &&
|
||||
!(pl = read_pool_disk(fmt, dev, mem, vginfo->vgname)))
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
if (info->dev &&
|
||||
!(pl = read_pool_disk(fmt, info->dev, mem, vginfo->vgname)))
|
||||
break;
|
||||
/*
|
||||
* We need to keep track of the total expected number
|
||||
* of devices per subpool
|
||||
*/
|
||||
if (!sp_count) {
|
||||
/* FIXME pl left uninitialised if !info->dev */
|
||||
sp_count = pl->pd.pl_subpools;
|
||||
if (!(sp_devs =
|
||||
pool_zalloc(tmpmem,
|
||||
@@ -298,9 +293,8 @@ static int _read_vg_pds(const struct format_type *fmt, struct pool *mem,
|
||||
}
|
||||
|
||||
*devcount = 0;
|
||||
for (i = 0; i < sp_count; i++) {
|
||||
for (i = 0; i < sp_count; i++)
|
||||
*devcount += sp_devs[i];
|
||||
}
|
||||
|
||||
pool_destroy(tmpmem);
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "metadata.h"
|
||||
#include "pool.h"
|
||||
|
||||
#define MINOR_OFFSET 65536
|
||||
|
||||
/* From NSP.cf */
|
||||
#define NSPMajorVersion 4
|
||||
#define NSPMinorVersion 1
|
||||
@@ -66,29 +68,6 @@ struct pool_list;
|
||||
struct user_subpool;
|
||||
struct user_device;
|
||||
|
||||
/* This must be kept up to date with sistina/pool/module/pool_sptypes.h */
|
||||
|
||||
/* Generic Labels */
|
||||
#define SPTYPE_DATA (0x00000000)
|
||||
|
||||
/* GFS specific labels */
|
||||
#define SPTYPE_GFS_DATA (0x68011670)
|
||||
#define SPTYPE_GFS_JOURNAL (0x69011670)
|
||||
|
||||
struct sptype_name {
|
||||
const char *name;
|
||||
uint32_t label;
|
||||
};
|
||||
|
||||
static const struct sptype_name sptype_names[] = {
|
||||
{"data", SPTYPE_DATA},
|
||||
|
||||
{"gfs_data", SPTYPE_GFS_DATA},
|
||||
{"gfs_journal", SPTYPE_GFS_JOURNAL},
|
||||
|
||||
{"", 0x0} /* This must be the last flag. */
|
||||
};
|
||||
|
||||
struct pool_disk {
|
||||
uint64_t pl_magic; /* Pool magic number */
|
||||
uint64_t pl_pool_id; /* Unique pool identifier */
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
static struct user_subpool *_build_usp(struct list *pls, struct pool *mem,
|
||||
int *sps)
|
||||
{
|
||||
|
||||
struct list *plhs;
|
||||
struct pool_list *pl;
|
||||
struct user_subpool *usp = NULL, *cur_sp = NULL;
|
||||
struct user_device *cur_dev = NULL;
|
||||
@@ -43,9 +41,7 @@ static struct user_subpool *_build_usp(struct list *pls, struct pool *mem,
|
||||
* FIXME: Need to do some checks here - I'm tempted to add a
|
||||
* user_pool structure and build the entire thing to check against.
|
||||
*/
|
||||
list_iterate(plhs, pls) {
|
||||
pl = list_item(plhs, struct pool_list);
|
||||
|
||||
list_iterate_items(pl, pls) {
|
||||
*sps = pl->pd.pl_subpools;
|
||||
if (!usp && (!(usp = pool_zalloc(mem, sizeof(*usp) * (*sps))))) {
|
||||
log_error("Unable to allocate %d subpool structures",
|
||||
@@ -72,13 +68,13 @@ static struct user_subpool *_build_usp(struct list *pls, struct pool *mem,
|
||||
"structures", pl->pd.pl_sp_devs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cur_dev = &cur_sp->devs[pl->pd.pl_sp_devid];
|
||||
cur_dev->sp_id = cur_sp->id;
|
||||
cur_dev->devid = pl->pd.pl_sp_id;
|
||||
cur_dev->blocks = pl->pd.pl_blocks;
|
||||
cur_dev->pv = pl->pv;
|
||||
cur_dev->initialized = 1;
|
||||
|
||||
}
|
||||
|
||||
return usp;
|
||||
@@ -132,7 +128,6 @@ static struct volume_group *_build_vg_from_pds(struct format_instance
|
||||
vg->system_id = NULL;
|
||||
list_init(&vg->pvs);
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
list_init(&vg->tags);
|
||||
|
||||
if (!import_pool_vg(vg, smem, pds)) {
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
#include "metadata.h"
|
||||
#include "lvmcache.h"
|
||||
#include "disk_rep.h"
|
||||
#include "sptype_names.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "pv_alloc.h"
|
||||
#include "str_list.h"
|
||||
#include "display.h"
|
||||
#include "segtype.h"
|
||||
@@ -28,12 +30,9 @@
|
||||
|
||||
int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls)
|
||||
{
|
||||
struct list *plhs;
|
||||
struct pool_list *pl;
|
||||
|
||||
list_iterate(plhs, pls) {
|
||||
pl = list_item(plhs, struct pool_list);
|
||||
|
||||
list_iterate_items(pl, pls) {
|
||||
vg->extent_count +=
|
||||
((pl->pd.pl_blocks) / POOL_PE_SIZE);
|
||||
|
||||
@@ -59,7 +58,6 @@ int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls)
|
||||
int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
|
||||
{
|
||||
struct pool_list *pl;
|
||||
struct list *plhs;
|
||||
struct lv_list *lvl = pool_zalloc(mem, sizeof(*lvl));
|
||||
struct logical_volume *lv;
|
||||
|
||||
@@ -81,12 +79,12 @@ int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
|
||||
lv->name = NULL;
|
||||
lv->le_count = 0;
|
||||
lv->read_ahead = 0;
|
||||
lv->snapshot = NULL;
|
||||
list_init(&lv->snapshot_segs);
|
||||
list_init(&lv->segments);
|
||||
list_init(&lv->tags);
|
||||
|
||||
list_iterate(plhs, pls) {
|
||||
pl = list_item(plhs, struct pool_list);
|
||||
|
||||
list_iterate_items(pl, pls) {
|
||||
lv->size += pl->pd.pl_blocks;
|
||||
|
||||
if (lv->name)
|
||||
@@ -107,10 +105,12 @@ int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
|
||||
/* for pool a minor of 0 is dynamic */
|
||||
if (pl->pd.pl_minor) {
|
||||
lv->status |= FIXED_MINOR;
|
||||
lv->minor = pl->pd.pl_minor;
|
||||
lv->minor = pl->pd.pl_minor + MINOR_OFFSET;
|
||||
} else {
|
||||
lv->minor = -1;
|
||||
}
|
||||
lv->snapshot = NULL;
|
||||
list_init(&lv->snapshot_segs);
|
||||
list_init(&lv->segments);
|
||||
list_init(&lv->tags);
|
||||
}
|
||||
@@ -128,11 +128,8 @@ int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg,
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
struct pool_list *pl;
|
||||
struct list *plhs;
|
||||
|
||||
list_iterate(plhs, pls) {
|
||||
pl = list_item(plhs, struct pool_list);
|
||||
|
||||
list_iterate_items(pl, pls) {
|
||||
if (!(pvl = pool_zalloc(mem, sizeof(*pvl)))) {
|
||||
log_error("Unable to allocate pv list structure");
|
||||
return 0;
|
||||
@@ -174,9 +171,15 @@ int import_pool_pv(const struct format_type *fmt, struct pool *mem,
|
||||
pv->pe_size = POOL_PE_SIZE;
|
||||
pv->pe_start = POOL_PE_START;
|
||||
pv->pe_count = pv->size / POOL_PE_SIZE;
|
||||
pv->pe_alloc_count = pv->pe_count;
|
||||
pv->pe_alloc_count = 0;
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
|
||||
if (!alloc_pv_segment_whole_pv(mem, pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -199,40 +202,44 @@ static int _add_stripe_seg(struct pool *mem,
|
||||
uint32_t *le_cur)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
int j;
|
||||
uint32_t area_len;
|
||||
|
||||
if (!(seg = alloc_lv_segment(mem, usp->num_devs))) {
|
||||
log_error("Unable to allocate striped lv_segment structure");
|
||||
return 0;
|
||||
}
|
||||
if(usp->striping & (usp->striping - 1)) {
|
||||
if (usp->striping & (usp->striping - 1)) {
|
||||
log_error("Stripe size must be a power of 2");
|
||||
return 0;
|
||||
}
|
||||
seg->stripe_size = usp->striping;
|
||||
seg->status |= 0;
|
||||
seg->le += *le_cur;
|
||||
|
||||
/* add the subpool type to the segment tag list */
|
||||
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
|
||||
area_len = (usp->devs[0].blocks) / POOL_PE_SIZE;
|
||||
|
||||
for (j = 0; j < usp->num_devs; j++) {
|
||||
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
|
||||
"striped"))) {
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd,
|
||||
"striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur,
|
||||
area_len * usp->num_devs, 0,
|
||||
usp->striping, NULL, usp->num_devs,
|
||||
area_len, 0, 0, 0))) {
|
||||
log_error("Unable to allocate striped lv_segment structure");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (j = 0; j < usp->num_devs; j++)
|
||||
if (!set_lv_segment_area_pv(seg, j, usp->devs[j].pv, 0)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
|
||||
seg->len += seg->area_len;
|
||||
*le_cur += seg->area_len;
|
||||
seg->lv = lv;
|
||||
/* add the subpool type to the segment tag list */
|
||||
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
|
||||
|
||||
seg->area[j].type = AREA_PV;
|
||||
seg->area[j].u.pv.pv = usp->devs[j].pv;
|
||||
seg->area[j].u.pv.pe = 0;
|
||||
}
|
||||
list_add(&lv->segments, &seg->list);
|
||||
|
||||
*le_cur += seg->len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -241,54 +248,56 @@ static int _add_linear_seg(struct pool *mem,
|
||||
uint32_t *le_cur)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
int j;
|
||||
uint32_t area_len;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (j = 0; j < usp->num_devs; j++) {
|
||||
/* linear segments only have 1 data area */
|
||||
if (!(seg = alloc_lv_segment(mem, 1))) {
|
||||
area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
|
||||
|
||||
if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur,
|
||||
area_len, 0, usp->striping,
|
||||
NULL, 1, area_len,
|
||||
POOL_PE_SIZE, 0, 0))) {
|
||||
log_error("Unable to allocate linear lv_segment "
|
||||
"structure");
|
||||
return 0;
|
||||
}
|
||||
seg->stripe_size = usp->striping;
|
||||
seg->le += *le_cur;
|
||||
seg->chunk_size = POOL_PE_SIZE;
|
||||
seg->status |= 0;
|
||||
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
|
||||
"striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* add the subpool type to the segment tag list */
|
||||
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
|
||||
|
||||
seg->lv = lv;
|
||||
|
||||
seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
|
||||
seg->len = seg->area_len;
|
||||
*le_cur += seg->len;
|
||||
seg->area[0].type = AREA_PV;
|
||||
seg->area[0].u.pv.pv = usp->devs[j].pv;
|
||||
seg->area[0].u.pv.pe = 0;
|
||||
if (!set_lv_segment_area_pv(seg, 0, usp->devs[j].pv, 0)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
list_add(&lv->segments, &seg->list);
|
||||
|
||||
*le_cur += seg->len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int import_pool_segments(struct list *lvs, struct pool *mem,
|
||||
struct user_subpool *usp, int subpools)
|
||||
{
|
||||
|
||||
struct list *lvhs;
|
||||
struct lv_list *lvl;
|
||||
struct logical_volume *lv;
|
||||
uint32_t le_cur = 0;
|
||||
int i;
|
||||
|
||||
list_iterate(lvhs, lvs) {
|
||||
lvl = list_item(lvhs, struct lv_list);
|
||||
|
||||
list_iterate_items(lvl, lvs) {
|
||||
lv = lvl->lv;
|
||||
|
||||
if (lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < subpools; i++) {
|
||||
if (usp[i].striping) {
|
||||
if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) {
|
||||
@@ -305,5 +314,4 @@ int import_pool_segments(struct list *lvs, struct pool *mem,
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
42
lib/format_pool/sptype_names.h
Normal file
42
lib/format_pool/sptype_names.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2005 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 SPTYPE_NAMES_H
|
||||
#define SPTYPE_NAMES_H
|
||||
|
||||
/* This must be kept up to date with sistina/pool/module/pool_sptypes.h */
|
||||
|
||||
/* Generic Labels */
|
||||
#define SPTYPE_DATA (0x00000000)
|
||||
|
||||
/* GFS specific labels */
|
||||
#define SPTYPE_GFS_DATA (0x68011670)
|
||||
#define SPTYPE_GFS_JOURNAL (0x69011670)
|
||||
|
||||
struct sptype_name {
|
||||
const char *name;
|
||||
uint32_t label;
|
||||
};
|
||||
|
||||
static const struct sptype_name sptype_names[] = {
|
||||
{"data", SPTYPE_DATA},
|
||||
|
||||
{"gfs_data", SPTYPE_GFS_DATA},
|
||||
{"gfs_journal", SPTYPE_GFS_JOURNAL},
|
||||
|
||||
{"", 0x0} /* This must be the last flag. */
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -53,7 +53,7 @@ struct archive_file {
|
||||
struct list list;
|
||||
|
||||
char *path;
|
||||
int index;
|
||||
uint32_t index;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -91,7 +91,6 @@ static int _split_vg(const char *filename, char *vgname, size_t vg_size,
|
||||
|
||||
static void _insert_file(struct list *head, struct archive_file *b)
|
||||
{
|
||||
struct list *bh;
|
||||
struct archive_file *bf = NULL;
|
||||
|
||||
if (list_empty(head)) {
|
||||
@@ -99,11 +98,9 @@ static void _insert_file(struct list *head, struct archive_file *b)
|
||||
return;
|
||||
}
|
||||
|
||||
/* index increases through list */
|
||||
list_iterate(bh, head) {
|
||||
bf = list_item(bh, struct archive_file);
|
||||
|
||||
if (bf->index > b->index) {
|
||||
/* index reduces through list */
|
||||
list_iterate_items(bf, head) {
|
||||
if (b->index > bf->index) {
|
||||
list_add(&bf->list, &b->list);
|
||||
return;
|
||||
}
|
||||
@@ -132,7 +129,8 @@ static char *_join(struct pool *mem, const char *dir, const char *name)
|
||||
static struct list *_scan_archive(struct pool *mem,
|
||||
const char *vgname, const char *dir)
|
||||
{
|
||||
int i, count, ix;
|
||||
int i, count;
|
||||
uint32_t ix;
|
||||
char vgname_found[64], *path;
|
||||
struct dirent **dirent;
|
||||
struct archive_file *af;
|
||||
@@ -147,13 +145,13 @@ static struct list *_scan_archive(struct pool *mem,
|
||||
|
||||
/* Sort fails beyond 5-digit indexes */
|
||||
if ((count = scandir(dir, &dirent, NULL, alphasort)) < 0) {
|
||||
log_err("Couldn't scan archive directory.");
|
||||
log_err("Couldn't scan the archive directory (%s).", dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
/* ignore dot files */
|
||||
if (dirent[i]->d_name[0] == '.')
|
||||
if (!strcmp(dirent[i]->d_name, ".") ||
|
||||
!strcmp(dirent[i]->d_name, ".."))
|
||||
continue;
|
||||
|
||||
/* check the name is the correct format */
|
||||
@@ -199,7 +197,6 @@ static struct list *_scan_archive(struct pool *mem,
|
||||
static void _remove_expired(struct list *archives, uint32_t archives_size,
|
||||
uint32_t retain_days, uint32_t min_archive)
|
||||
{
|
||||
struct list *bh;
|
||||
struct archive_file *bf;
|
||||
struct stat sb;
|
||||
time_t retain_time;
|
||||
@@ -213,9 +210,7 @@ static void _remove_expired(struct list *archives, uint32_t archives_size,
|
||||
retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY;
|
||||
|
||||
/* Assume list is ordered oldest first (by index) */
|
||||
list_iterate(bh, archives) {
|
||||
bf = list_item(bh, struct archive_file);
|
||||
|
||||
list_iterate_items(bf, archives) {
|
||||
/* Get the mtime of the file and unlink if too old */
|
||||
if (stat(bf->path, &sb)) {
|
||||
log_sys_error("stat", bf->path);
|
||||
@@ -240,7 +235,7 @@ int archive_vg(struct volume_group *vg,
|
||||
uint32_t retain_days, uint32_t min_archive)
|
||||
{
|
||||
int i, fd, renamed = 0;
|
||||
unsigned int ix = 0;
|
||||
uint32_t ix = 0;
|
||||
struct archive_file *last;
|
||||
FILE *fp = NULL;
|
||||
char temp_file[PATH_MAX], archive_name[PATH_MAX];
|
||||
@@ -272,20 +267,20 @@ int archive_vg(struct volume_group *vg,
|
||||
* Now we want to rename this file to <vg>_index.vg.
|
||||
*/
|
||||
if (!(archives = _scan_archive(vg->cmd->mem, vg->name, dir))) {
|
||||
log_err("Couldn't scan the archive directory (%s).", dir);
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (list_empty(archives))
|
||||
ix = 0;
|
||||
else {
|
||||
last = list_item(archives->p, struct archive_file);
|
||||
last = list_item(list_first(archives), struct archive_file);
|
||||
ix = last->index + 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (lvm_snprintf(archive_name, sizeof(archive_name),
|
||||
"%s/%s_%05d.vg", dir, vg->name, ix) < 0) {
|
||||
"%s/%s_%05u.vg", dir, vg->name, ix) < 0) {
|
||||
log_error("Archive file name too long.");
|
||||
return 0;
|
||||
}
|
||||
@@ -344,22 +339,19 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
|
||||
|
||||
int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname)
|
||||
{
|
||||
struct list *archives, *ah;
|
||||
struct list *archives;
|
||||
struct archive_file *af;
|
||||
|
||||
if (!(archives = _scan_archive(cmd->mem, vgname, dir))) {
|
||||
log_err("Couldn't scan the archive directory (%s).", dir);
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (list_empty(archives))
|
||||
log_print("No archives found in %s.", dir);
|
||||
|
||||
list_iterate(ah, archives) {
|
||||
af = list_item(ah, struct archive_file);
|
||||
|
||||
list_iterate_back_items(af, archives)
|
||||
_display_archive(cmd, af);
|
||||
}
|
||||
|
||||
pool_free(cmd->mem, archives);
|
||||
|
||||
|
||||
@@ -13,53 +13,64 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "tools.h"
|
||||
#include "lib.h"
|
||||
#include "archiver.h"
|
||||
#include "format-text.h"
|
||||
#include "lvm-file.h"
|
||||
#include "lvm-string.h"
|
||||
#include "lvmcache.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
static struct {
|
||||
#include <unistd.h>
|
||||
|
||||
struct archive_params {
|
||||
int enabled;
|
||||
char *dir;
|
||||
unsigned int keep_days;
|
||||
unsigned int keep_number;
|
||||
};
|
||||
|
||||
} _archive_params;
|
||||
|
||||
static struct {
|
||||
struct backup_params {
|
||||
int enabled;
|
||||
char *dir;
|
||||
};
|
||||
|
||||
} _backup_params;
|
||||
|
||||
int archive_init(const char *dir, unsigned int keep_days, unsigned int keep_min)
|
||||
int archive_init(struct cmd_context *cmd, const char *dir,
|
||||
unsigned int keep_days, unsigned int keep_min)
|
||||
{
|
||||
_archive_params.dir = NULL;
|
||||
if (!(cmd->archive_params = pool_zalloc(cmd->libmem,
|
||||
sizeof(*cmd->archive_params)))) {
|
||||
log_error("archive_params alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd->archive_params->dir = NULL;
|
||||
|
||||
if (!*dir)
|
||||
return 1;
|
||||
|
||||
if (!create_dir(dir))
|
||||
return 0;
|
||||
|
||||
if (!(_archive_params.dir = dbg_strdup(dir))) {
|
||||
if (!(cmd->archive_params->dir = dbg_strdup(dir))) {
|
||||
log_error("Couldn't copy archive directory name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
_archive_params.keep_days = keep_days;
|
||||
_archive_params.keep_number = keep_min;
|
||||
_archive_params.enabled = 1;
|
||||
cmd->archive_params->keep_days = keep_days;
|
||||
cmd->archive_params->keep_number = keep_min;
|
||||
cmd->archive_params->enabled = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void archive_exit(void)
|
||||
void archive_exit(struct cmd_context *cmd)
|
||||
{
|
||||
if (_archive_params.dir)
|
||||
dbg_free(_archive_params.dir);
|
||||
memset(&_archive_params, 0, sizeof(_archive_params));
|
||||
if (cmd->archive_params->dir)
|
||||
dbg_free(cmd->archive_params->dir);
|
||||
memset(cmd->archive_params, 0, sizeof(*cmd->archive_params));
|
||||
}
|
||||
|
||||
void archive_enable(int flag)
|
||||
void archive_enable(struct cmd_context *cmd, int flag)
|
||||
{
|
||||
_archive_params.enabled = flag;
|
||||
cmd->archive_params->enabled = flag;
|
||||
}
|
||||
|
||||
static char *_build_desc(struct pool *mem, const char *line, int before)
|
||||
@@ -91,14 +102,14 @@ static int __archive(struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return archive_vg(vg, _archive_params.dir, desc,
|
||||
_archive_params.keep_days,
|
||||
_archive_params.keep_number);
|
||||
return archive_vg(vg, vg->cmd->archive_params->dir, desc,
|
||||
vg->cmd->archive_params->keep_days,
|
||||
vg->cmd->archive_params->keep_number);
|
||||
}
|
||||
|
||||
int archive(struct volume_group *vg)
|
||||
{
|
||||
if (!_archive_params.enabled || !_archive_params.dir)
|
||||
if (!vg->cmd->archive_params->enabled || !vg->cmd->archive_params->dir)
|
||||
return 1;
|
||||
|
||||
if (test_mode()) {
|
||||
@@ -106,7 +117,16 @@ int archive(struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_verbose("Archiving volume group \"%s\" metadata.", vg->name);
|
||||
if (!create_dir(vg->cmd->archive_params->dir))
|
||||
return 0;
|
||||
|
||||
/* Trap a read-only file system */
|
||||
if ((access(vg->cmd->archive_params->dir, R_OK | W_OK | X_OK) == -1) &&
|
||||
(errno == EROFS))
|
||||
return 0;
|
||||
|
||||
log_verbose("Archiving volume group \"%s\" metadata (seqno %u).", vg->name,
|
||||
vg->seqno);
|
||||
if (!__archive(vg)) {
|
||||
log_error("Volume group \"%s\" metadata archive failed.",
|
||||
vg->name);
|
||||
@@ -121,23 +141,26 @@ int archive_display(struct cmd_context *cmd, const char *vg_name)
|
||||
int r1, r2;
|
||||
|
||||
init_partial(1);
|
||||
r1 = archive_list(cmd, _archive_params.dir, vg_name);
|
||||
r2 = backup_list(cmd, _backup_params.dir, vg_name);
|
||||
r1 = archive_list(cmd, cmd->archive_params->dir, vg_name);
|
||||
r2 = backup_list(cmd, cmd->backup_params->dir, vg_name);
|
||||
init_partial(0);
|
||||
|
||||
return r1 && r2;
|
||||
}
|
||||
|
||||
int backup_init(const char *dir)
|
||||
int backup_init(struct cmd_context *cmd, const char *dir)
|
||||
{
|
||||
_backup_params.dir = NULL;
|
||||
if (!(cmd->backup_params = pool_zalloc(cmd->libmem,
|
||||
sizeof(*cmd->archive_params)))) {
|
||||
log_error("archive_params alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd->backup_params->dir = NULL;
|
||||
if (!*dir)
|
||||
return 1;
|
||||
|
||||
if (!create_dir(dir))
|
||||
return 0;
|
||||
|
||||
if (!(_backup_params.dir = dbg_strdup(dir))) {
|
||||
if (!(cmd->backup_params->dir = dbg_strdup(dir))) {
|
||||
log_error("Couldn't copy backup directory name.");
|
||||
return 0;
|
||||
}
|
||||
@@ -145,16 +168,16 @@ int backup_init(const char *dir)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void backup_exit(void)
|
||||
void backup_exit(struct cmd_context *cmd)
|
||||
{
|
||||
if (_backup_params.dir)
|
||||
dbg_free(_backup_params.dir);
|
||||
memset(&_backup_params, 0, sizeof(_backup_params));
|
||||
if (cmd->backup_params->dir)
|
||||
dbg_free(cmd->backup_params->dir);
|
||||
memset(cmd->backup_params, 0, sizeof(*cmd->backup_params));
|
||||
}
|
||||
|
||||
void backup_enable(int flag)
|
||||
void backup_enable(struct cmd_context *cmd, int flag)
|
||||
{
|
||||
_backup_params.enabled = flag;
|
||||
cmd->backup_params->enabled = flag;
|
||||
}
|
||||
|
||||
static int __backup(struct volume_group *vg)
|
||||
@@ -168,7 +191,7 @@ static int __backup(struct volume_group *vg)
|
||||
}
|
||||
|
||||
if (lvm_snprintf(name, sizeof(name), "%s/%s",
|
||||
_backup_params.dir, vg->name) < 0) {
|
||||
vg->cmd->backup_params->dir, vg->name) < 0) {
|
||||
log_error("Failed to generate volume group metadata backup "
|
||||
"filename.");
|
||||
return 0;
|
||||
@@ -179,7 +202,7 @@ static int __backup(struct volume_group *vg)
|
||||
|
||||
int backup(struct volume_group *vg)
|
||||
{
|
||||
if (!_backup_params.enabled || !_backup_params.dir) {
|
||||
if (!vg->cmd->backup_params->enabled || !vg->cmd->backup_params->dir) {
|
||||
log_print("WARNING: This metadata update is NOT backed up");
|
||||
return 1;
|
||||
}
|
||||
@@ -189,6 +212,14 @@ int backup(struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!create_dir(vg->cmd->backup_params->dir))
|
||||
return 0;
|
||||
|
||||
/* Trap a read-only file system */
|
||||
if ((access(vg->cmd->backup_params->dir, R_OK | W_OK | X_OK) == -1) &&
|
||||
(errno == EROFS))
|
||||
return 0;
|
||||
|
||||
if (!__backup(vg)) {
|
||||
log_error("Backup of volume group %s metadata failed.",
|
||||
vg->name);
|
||||
@@ -198,12 +229,12 @@ int backup(struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int backup_remove(const char *vg_name)
|
||||
int backup_remove(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (lvm_snprintf(path, sizeof(path), "%s/%s",
|
||||
_backup_params.dir, vg_name) < 0) {
|
||||
cmd->backup_params->dir, vg_name) < 0) {
|
||||
log_err("Failed to generate backup filename (for removal).");
|
||||
return 0;
|
||||
}
|
||||
@@ -269,7 +300,7 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
if (cmd->fmt != info->fmt) {
|
||||
log_error("PV %s is a different format (%s)",
|
||||
log_error("PV %s is a different format (seqno %s)",
|
||||
dev_name(pv->dev), info->fmt->name);
|
||||
return 0;
|
||||
}
|
||||
@@ -312,7 +343,7 @@ int backup_restore(struct cmd_context *cmd, const char *vg_name)
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (lvm_snprintf(path, sizeof(path), "%s/%s",
|
||||
_backup_params.dir, vg_name) < 0) {
|
||||
cmd->backup_params->dir, vg_name) < 0) {
|
||||
log_err("Failed to generate backup filename (for restore).");
|
||||
return 0;
|
||||
}
|
||||
@@ -330,7 +361,7 @@ int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
|
||||
|
||||
cmd = vg->cmd;
|
||||
|
||||
log_verbose("Creating volume group backup \"%s\"", file);
|
||||
log_verbose("Creating volume group backup \"%s\" (seqno %u).", file, vg->seqno);
|
||||
|
||||
if (!(context = create_text_context(cmd, file, desc)) ||
|
||||
!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
|
||||
@@ -354,3 +385,34 @@ int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
|
||||
tf->fmt->ops->destroy_instance(tf);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update backup (and archive) if they're out-of-date or don't exist.
|
||||
*/
|
||||
void check_current_backup(struct volume_group *vg)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
struct volume_group *vg_backup;
|
||||
|
||||
if ((vg->status & PARTIAL_VG) || (vg->status & EXPORTED_VG))
|
||||
return;
|
||||
|
||||
if (lvm_snprintf(path, sizeof(path), "%s/%s",
|
||||
vg->cmd->backup_params->dir, vg->name) < 0) {
|
||||
log_debug("Failed to generate backup filename.");
|
||||
return;
|
||||
}
|
||||
|
||||
log_suppress(1);
|
||||
/* Up-to-date backup exists? */
|
||||
if ((vg_backup = backup_read_vg(vg->cmd, vg->name, path)) &&
|
||||
(vg->seqno == vg_backup->seqno) &&
|
||||
(id_equal(&vg->id, &vg_backup->id)))
|
||||
return;
|
||||
log_suppress(0);
|
||||
|
||||
if (vg_backup)
|
||||
archive(vg_backup);
|
||||
archive(vg);
|
||||
backup(vg);
|
||||
}
|
||||
@@ -18,11 +18,6 @@
|
||||
|
||||
#include "metadata.h"
|
||||
|
||||
/*
|
||||
* FIXME: This file is going to merge with the archiving code in
|
||||
* lib/format_text at some point.
|
||||
*/
|
||||
|
||||
/*
|
||||
* There are two operations that come under the general area of
|
||||
* backups. 'Archiving' occurs just before a volume group
|
||||
@@ -36,20 +31,20 @@
|
||||
* Typically backups will be stored in /etc/lvm/backups.
|
||||
*/
|
||||
|
||||
int archive_init(const char *dir,
|
||||
int archive_init(struct cmd_context *cmd, const char *dir,
|
||||
unsigned int keep_days, unsigned int keep_min);
|
||||
void archive_exit(void);
|
||||
void archive_exit(struct cmd_context *cmd);
|
||||
|
||||
void archive_enable(int flag);
|
||||
void archive_enable(struct cmd_context *cmd, int flag);
|
||||
int archive(struct volume_group *vg);
|
||||
int archive_display(struct cmd_context *cmd, const char *vg_name);
|
||||
|
||||
int backup_init(const char *dir);
|
||||
void backup_exit(void);
|
||||
int backup_init(struct cmd_context *cmd, const char *dir);
|
||||
void backup_exit(struct cmd_context *cmd);
|
||||
|
||||
void backup_enable(int flag);
|
||||
void backup_enable(struct cmd_context *cmd, int flag);
|
||||
int backup(struct volume_group *vg);
|
||||
int backup_remove(const char *vg_name);
|
||||
int backup_remove(struct cmd_context *cmd, const char *vg_name);
|
||||
|
||||
struct volume_group *backup_read_vg(struct cmd_context *cmd,
|
||||
const char *vg_name, const char *file);
|
||||
@@ -60,4 +55,6 @@ int backup_restore(struct cmd_context *cmd, const char *vg_name);
|
||||
|
||||
int backup_to_file(const char *file, const char *desc, struct volume_group *vg);
|
||||
|
||||
void check_current_backup(struct volume_group *vg);
|
||||
|
||||
#endif
|
||||
@@ -30,7 +30,7 @@
|
||||
struct formatter;
|
||||
typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
|
||||
const char *fmt, va_list ap);
|
||||
typedef void (*nl_fn) (struct formatter * f);
|
||||
typedef int (*nl_fn) (struct formatter * f);
|
||||
/*
|
||||
* The first half of this file deals with
|
||||
* exporting the vg, ie. writing it to a file.
|
||||
@@ -42,7 +42,7 @@ struct formatter {
|
||||
union {
|
||||
FILE *fp; /* where we're writing to */
|
||||
struct {
|
||||
char *buf;
|
||||
char *start;
|
||||
uint32_t size;
|
||||
uint32_t used;
|
||||
} buf;
|
||||
@@ -95,22 +95,34 @@ static void _dec_indent(struct formatter *f)
|
||||
/*
|
||||
* Newline function for prettier layout.
|
||||
*/
|
||||
static void _nl_file(struct formatter *f)
|
||||
static int _nl_file(struct formatter *f)
|
||||
{
|
||||
fprintf(f->data.fp, "\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _nl_raw(struct formatter *f)
|
||||
static int _nl_raw(struct formatter *f)
|
||||
{
|
||||
if (f->data.buf.used >= f->data.buf.size - 1)
|
||||
return;
|
||||
char *newbuf;
|
||||
|
||||
*f->data.buf.buf = '\n';
|
||||
f->data.buf.buf += 1;
|
||||
/* If metadata doesn't fit, double the buffer size */
|
||||
if (f->data.buf.used + 2 > f->data.buf.size) {
|
||||
if (!(newbuf = dbg_realloc(f->data.buf.start,
|
||||
f->data.buf.size * 2))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
f->data.buf.start = newbuf;
|
||||
f->data.buf.size *= 2;
|
||||
}
|
||||
|
||||
*(f->data.buf.start + f->data.buf.used) = '\n';
|
||||
f->data.buf.used += 1;
|
||||
*f->data.buf.buf = '\0';
|
||||
|
||||
return;
|
||||
*(f->data.buf.start + f->data.buf.used) = '\0';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define COMMENT_TAB 6
|
||||
@@ -153,17 +165,27 @@ static int _out_with_comment_raw(struct formatter *f, const char *comment,
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
int n;
|
||||
char *newbuf;
|
||||
|
||||
n = vsnprintf(f->data.buf.buf, f->data.buf.size - f->data.buf.used,
|
||||
fmt, ap);
|
||||
retry:
|
||||
n = vsnprintf(f->data.buf.start + f->data.buf.used,
|
||||
f->data.buf.size - f->data.buf.used, fmt, ap);
|
||||
|
||||
if (n < 0 || (n > f->data.buf.size - f->data.buf.used - 1))
|
||||
return 0;
|
||||
/* If metadata doesn't fit, double the buffer size */
|
||||
if (n < 0 || (n + f->data.buf.used + 2 > f->data.buf.size)) {
|
||||
if (!(newbuf = dbg_realloc(f->data.buf.start,
|
||||
f->data.buf.size * 2))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
f->data.buf.start = newbuf;
|
||||
f->data.buf.size *= 2;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
f->data.buf.buf += n;
|
||||
f->data.buf.used += n;
|
||||
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -257,10 +279,10 @@ static int _print_header(struct formatter *f,
|
||||
outf(f, "# Generated by LVM2: %s", ctime(&t));
|
||||
outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
|
||||
outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
|
||||
outf(f, "description = \"%s\"", desc);
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
|
||||
_utsname.sysname, _utsname.nodename, _utsname.release,
|
||||
_utsname.version, _utsname.machine);
|
||||
@@ -309,7 +331,7 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
|
||||
/* Default policy is NORMAL; INHERIT is meaningless */
|
||||
if (vg->alloc != ALLOC_NORMAL && vg->alloc != ALLOC_INHERIT) {
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
outf(f, "allocation_policy = \"%s\"",
|
||||
get_alloc_string(vg->alloc));
|
||||
}
|
||||
@@ -330,7 +352,7 @@ static inline const char *_get_pv_name(struct formatter *f,
|
||||
|
||||
static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
struct physical_volume *pv;
|
||||
char buffer[4096];
|
||||
const char *name;
|
||||
@@ -338,15 +360,15 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
outf(f, "physical_volumes {");
|
||||
_inc_indent(f);
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
pv = pvl->pv;
|
||||
|
||||
if (!(name = _get_pv_name(f, pv))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
outf(f, "%s {", name);
|
||||
_inc_indent(f);
|
||||
|
||||
@@ -360,7 +382,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
|
||||
if (!print_flags(pv->status, PV_FLAGS, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
@@ -407,7 +429,7 @@ static int _print_segment(struct formatter *f, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
outf(f, "type = \"%s\"", seg->segtype->name);
|
||||
|
||||
if (!list_empty(&seg->tags)) {
|
||||
@@ -436,27 +458,27 @@ int out_areas(struct formatter *f, const struct lv_segment *seg,
|
||||
const char *name;
|
||||
unsigned int s;
|
||||
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
|
||||
outf(f, "%ss = [", type);
|
||||
_inc_indent(f);
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
switch (seg->area[s].type) {
|
||||
switch (seg_type(seg, s)) {
|
||||
case AREA_PV:
|
||||
if (!(name = _get_pv_name(f, seg->area[s].u.pv.pv))) {
|
||||
if (!(name = _get_pv_name(f, seg_pv(seg, s)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
outf(f, "\"%s\", %u%s", name,
|
||||
seg->area[s].u.pv.pe,
|
||||
seg_pe(seg, s),
|
||||
(s == seg->area_count - 1) ? "" : ",");
|
||||
break;
|
||||
case AREA_LV:
|
||||
outf(f, "\"%s\", %u%s",
|
||||
seg->area[s].u.lv.lv->name,
|
||||
seg->area[s].u.lv.le,
|
||||
seg_lv(seg, s)->name,
|
||||
seg_le(seg, s),
|
||||
(s == seg->area_count - 1) ? "" : ",");
|
||||
}
|
||||
}
|
||||
@@ -466,72 +488,57 @@ int out_areas(struct formatter *f, const struct lv_segment *seg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _count_segments(struct logical_volume *lv)
|
||||
static int _print_lv(struct formatter *f, struct logical_volume *lv)
|
||||
{
|
||||
int r = 0;
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
char buffer[4096];
|
||||
int seg_count;
|
||||
|
||||
list_iterate(segh, &lv->segments)
|
||||
r++;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _print_snapshot(struct formatter *f, struct snapshot *snap,
|
||||
unsigned int count)
|
||||
{
|
||||
char buffer[256];
|
||||
struct lv_segment seg;
|
||||
|
||||
f->nl(f);
|
||||
|
||||
outf(f, "snapshot%u {", count);
|
||||
outnl(f);
|
||||
outf(f, "%s {", lv->name);
|
||||
_inc_indent(f);
|
||||
|
||||
if (!id_write_format(&snap->id, buffer, sizeof(buffer))) {
|
||||
/* FIXME: Write full lvid */
|
||||
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
outf(f, "id = \"%s\"", buffer);
|
||||
|
||||
seg.status = LVM_READ | LVM_WRITE | VISIBLE_LV;
|
||||
if (!print_flags(seg.status, LV_FLAGS, buffer, sizeof(buffer))) {
|
||||
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
outf(f, "status = %s", buffer);
|
||||
outf(f, "segment_count = 1");
|
||||
|
||||
f->nl(f);
|
||||
|
||||
if (!(seg.segtype = get_segtype_from_string(snap->origin->vg->cmd,
|
||||
"snapshot"))) {
|
||||
stack;
|
||||
return 0;
|
||||
if (!list_empty(&lv->tags)) {
|
||||
if (!print_tags(&lv->tags, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
outf(f, "tags = %s", buffer);
|
||||
}
|
||||
|
||||
seg.le = 0;
|
||||
seg.len = snap->origin->le_count;
|
||||
seg.origin = snap->origin;
|
||||
seg.cow = snap->cow;
|
||||
seg.chunk_size = snap->chunk_size;
|
||||
if (lv->alloc != ALLOC_INHERIT)
|
||||
outf(f, "allocation_policy = \"%s\"",
|
||||
get_alloc_string(lv->alloc));
|
||||
|
||||
/* FIXME Dummy values */
|
||||
list_init(&seg.list);
|
||||
seg.lv = snap->cow;
|
||||
seg.stripe_size = 0;
|
||||
seg.area_count = 0;
|
||||
seg.area_len = 0;
|
||||
seg.extents_copied = 0;
|
||||
if (lv->read_ahead)
|
||||
outf(f, "read_ahead = %u", lv->read_ahead);
|
||||
if (lv->major >= 0)
|
||||
outf(f, "major = %d", lv->major);
|
||||
if (lv->minor >= 0)
|
||||
outf(f, "minor = %d", lv->minor);
|
||||
outf(f, "segment_count = %u", list_size(&lv->segments));
|
||||
outnl(f);
|
||||
|
||||
/* Can't tag a snapshot independently of its origin */
|
||||
list_init(&seg.tags);
|
||||
|
||||
if (!_print_segment(f, snap->origin->vg, 1, &seg)) {
|
||||
stack;
|
||||
return 0;
|
||||
seg_count = 1;
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (!_print_segment(f, lv->vg, seg_count++, seg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
@@ -540,31 +547,9 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_snapshots(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
struct list *sh;
|
||||
struct snapshot *s;
|
||||
unsigned int count = 0;
|
||||
|
||||
list_iterate(sh, &vg->snapshots) {
|
||||
s = list_item(sh, struct snapshot_list)->snapshot;
|
||||
|
||||
if (!_print_snapshot(f, s, count++)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_segment *seg;
|
||||
char buffer[4096];
|
||||
int seg_count;
|
||||
struct lv_list *lvl;
|
||||
|
||||
/*
|
||||
* Don't bother with an lv section if there are no lvs.
|
||||
@@ -575,63 +560,25 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
outf(f, "logical_volumes {");
|
||||
_inc_indent(f);
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
|
||||
f->nl(f);
|
||||
outf(f, "%s {", lv->name);
|
||||
_inc_indent(f);
|
||||
|
||||
/* FIXME: Write full lvid */
|
||||
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
|
||||
/*
|
||||
* Write visible LVs first
|
||||
*/
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if (!(lvl->lv->status & VISIBLE_LV))
|
||||
continue;
|
||||
if (!_print_lv(f, lvl->lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
outf(f, "id = \"%s\"", buffer);
|
||||
|
||||
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
outf(f, "status = %s", buffer);
|
||||
|
||||
if (!list_empty(&lv->tags)) {
|
||||
if (!print_tags(&lv->tags, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
outf(f, "tags = %s", buffer);
|
||||
}
|
||||
|
||||
if (lv->alloc != ALLOC_INHERIT)
|
||||
outf(f, "allocation_policy = \"%s\"",
|
||||
get_alloc_string(lv->alloc));
|
||||
|
||||
if (lv->read_ahead)
|
||||
outf(f, "read_ahead = %u", lv->read_ahead);
|
||||
if (lv->major >= 0)
|
||||
outf(f, "major = %d", lv->major);
|
||||
if (lv->minor >= 0)
|
||||
outf(f, "minor = %d", lv->minor);
|
||||
outf(f, "segment_count = %u", _count_segments(lv));
|
||||
f->nl(f);
|
||||
|
||||
seg_count = 1;
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (!_print_segment(f, vg, seg_count++, seg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
outf(f, "}");
|
||||
}
|
||||
|
||||
if (!_print_snapshots(f, vg)) {
|
||||
stack;
|
||||
return 0;
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if ((lvl->lv->status & VISIBLE_LV))
|
||||
continue;
|
||||
if (!_print_lv(f, lvl->lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
@@ -648,7 +595,7 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
static int _build_pv_names(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
int count = 0;
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
struct physical_volume *pv;
|
||||
char buffer[32], *name;
|
||||
|
||||
@@ -662,8 +609,8 @@ static int _build_pv_names(struct formatter *f, struct volume_group *vg)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
pv = pvl->pv;
|
||||
|
||||
/* FIXME But skip if there's already an LV called pv%d ! */
|
||||
if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) {
|
||||
@@ -716,11 +663,11 @@ static int _text_vg_export(struct formatter *f,
|
||||
if (!_print_vg(f, vg))
|
||||
fail;
|
||||
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
if (!_print_pvs(f, vg))
|
||||
fail;
|
||||
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
if (!_print_lvs(f, vg))
|
||||
fail;
|
||||
|
||||
@@ -771,11 +718,10 @@ int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp)
|
||||
}
|
||||
|
||||
/* Returns amount of buffer used incl. terminating NUL */
|
||||
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||
uint32_t size)
|
||||
int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
|
||||
{
|
||||
struct formatter *f;
|
||||
int r;
|
||||
int r = 0;
|
||||
|
||||
_init();
|
||||
|
||||
@@ -785,8 +731,13 @@ int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||
}
|
||||
|
||||
memset(f, 0, sizeof(*f));
|
||||
f->data.buf.buf = buf;
|
||||
f->data.buf.size = size;
|
||||
|
||||
f->data.buf.size = 65536; /* Initial metadata limit */
|
||||
if (!(f->data.buf.start = dbg_malloc(f->data.buf.size))) {
|
||||
log_error("text_export buffer allocation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
f->indent = 0;
|
||||
f->header = 0;
|
||||
f->out_with_comment = &_out_with_comment_raw;
|
||||
@@ -794,11 +745,12 @@ int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||
|
||||
if (!_text_vg_export(f, vg, desc)) {
|
||||
stack;
|
||||
r = 0;
|
||||
dbg_free(f->data.buf.start);
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = f->data.buf.used + 1;
|
||||
*buf = f->data.buf.start;
|
||||
|
||||
out:
|
||||
dbg_free(f);
|
||||
@@ -806,3 +758,4 @@ int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||
}
|
||||
|
||||
#undef outf
|
||||
#undef outnl
|
||||
|
||||
@@ -52,8 +52,11 @@ static struct flag _lv_flags[] = {
|
||||
{VISIBLE_LV, "VISIBLE"},
|
||||
{PVMOVE, "PVMOVE"},
|
||||
{LOCKED, "LOCKED"},
|
||||
{MIRROR_IMAGE, NULL},
|
||||
{MIRROR_LOG, NULL},
|
||||
{MIRRORED, NULL},
|
||||
{VIRTUAL, NULL},
|
||||
{SNAPSHOT, NULL},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
|
||||
@@ -88,8 +88,11 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
|
||||
}
|
||||
*/
|
||||
|
||||
if (!*lv->lvid.s)
|
||||
lvid_create(&lv->lvid, &lv->vg->id);
|
||||
if (!*lv->lvid.s && !lvid_create(&lv->lvid, &lv->vg->id)) {
|
||||
log_error("Random lvid creation failed for %s/%s.",
|
||||
lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -180,57 +183,74 @@ static int _raw_write_mda_header(const struct format_type *fmt,
|
||||
|
||||
static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
|
||||
struct mda_header *mdah,
|
||||
const char *vgname)
|
||||
const char *vgname,
|
||||
int precommit)
|
||||
{
|
||||
size_t len;
|
||||
char vgnamebuf[NAME_LEN + 2];
|
||||
struct raw_locn *rlocn;
|
||||
struct lvmcache_info *info;
|
||||
|
||||
rlocn = mdah->raw_locns;
|
||||
rlocn = mdah->raw_locns; /* Slot 0 */
|
||||
|
||||
if (precommit)
|
||||
rlocn++; /* Slot 1 */
|
||||
|
||||
/* FIXME Loop through rlocns two-at-a-time. List null-terminated. */
|
||||
/* FIXME Ignore if checksum incorrect!!! */
|
||||
while (rlocn->offset) {
|
||||
if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
|
||||
sizeof(vgnamebuf), vgnamebuf)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
|
||||
(isspace(vgnamebuf[len]) || vgnamebuf[len] == '{')) {
|
||||
return rlocn;
|
||||
}
|
||||
rlocn++;
|
||||
if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
|
||||
sizeof(vgnamebuf), vgnamebuf)) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
|
||||
(isspace(vgnamebuf[len]) || vgnamebuf[len] == '{')) {
|
||||
return rlocn;
|
||||
}
|
||||
|
||||
error:
|
||||
if ((info = info_from_pvid(dev_area->dev->pvid)))
|
||||
lvmcache_update_vgname(info, ORPHAN);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct raw_locn *_vg_posn(struct format_instance *fid,
|
||||
struct device_area *dev_area,
|
||||
const char *vgname)
|
||||
/*
|
||||
* Determine offset for uncommitted metadata
|
||||
*/
|
||||
static uint64_t _next_rlocn_offset(struct raw_locn *rlocn,
|
||||
struct mda_header *mdah)
|
||||
{
|
||||
if (!rlocn)
|
||||
/* Find an empty slot */
|
||||
/* FIXME Assume only one VG per mdah for now */
|
||||
return MDA_HEADER_SIZE;
|
||||
|
||||
struct mda_header *mdah;
|
||||
|
||||
if (!(mdah = _raw_read_mda_header(fid->fmt, dev_area))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return _find_vg_rlocn(dev_area, mdah, vgname);
|
||||
/* Start of free space - round up to next sector; circular */
|
||||
return ((rlocn->offset + rlocn->size +
|
||||
(SECTOR_SIZE - rlocn->size % SECTOR_SIZE) -
|
||||
MDA_HEADER_SIZE) % (mdah->size - MDA_HEADER_SIZE))
|
||||
+ MDA_HEADER_SIZE;
|
||||
}
|
||||
|
||||
static int _raw_holds_vgname(struct format_instance *fid,
|
||||
struct device_area *dev_area, const char *vgname)
|
||||
{
|
||||
int r = 0;
|
||||
struct mda_header *mdah;
|
||||
|
||||
if (!dev_open(dev_area->dev)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_vg_posn(fid, dev_area, vgname))
|
||||
if (!(mdah = _raw_read_mda_header(fid->fmt, dev_area))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_find_vg_rlocn(dev_area, mdah, vgname, 0))
|
||||
r = 1;
|
||||
|
||||
if (!dev_close(dev_area->dev))
|
||||
@@ -241,7 +261,8 @@ static int _raw_holds_vgname(struct format_instance *fid,
|
||||
|
||||
static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct device_area *area)
|
||||
struct device_area *area,
|
||||
int precommit)
|
||||
{
|
||||
struct volume_group *vg = NULL;
|
||||
struct raw_locn *rlocn;
|
||||
@@ -260,8 +281,8 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(rlocn = _vg_posn(fid, area, vgname))) {
|
||||
stack;
|
||||
if (!(rlocn = _find_vg_rlocn(area, mdah, vgname, precommit))) {
|
||||
log_debug("VG %s not found on %s", vgname, dev_name(area->dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -284,8 +305,9 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
log_debug("Read %s metadata (%u) from %s at %" PRIu64 " size %" PRIu64,
|
||||
vg->name, vg->seqno, dev_name(area->dev),
|
||||
log_debug("Read %s %smetadata (%u) from %s at %" PRIu64 " size %"
|
||||
PRIu64, vg->name, precommit ? "pre-commit " : "",
|
||||
vg->seqno, dev_name(area->dev),
|
||||
area->start + rlocn->offset, rlocn->size);
|
||||
|
||||
out:
|
||||
@@ -301,7 +323,16 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
|
||||
return _vg_read_raw_area(fid, vgname, &mdac->area);
|
||||
return _vg_read_raw_area(fid, vgname, &mdac->area, 0);
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
|
||||
return _vg_read_raw_area(fid, vgname, &mdac->area, 1);
|
||||
}
|
||||
|
||||
static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
@@ -310,19 +341,15 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct raw_locn *rlocn;
|
||||
struct mda_header *mdah;
|
||||
struct physical_volume *pv;
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
int r = 0;
|
||||
uint32_t new_wrap = 0, old_wrap = 0;
|
||||
|
||||
/* FIXME Essential fix! Make dynamic (realloc? pool?) */
|
||||
char buf[65536];
|
||||
char *buf = NULL;
|
||||
int found = 0;
|
||||
|
||||
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
if (pv->dev == mdac->area.dev) {
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (pvl->pv->dev == mdac->area.dev) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
@@ -341,20 +368,10 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
|
||||
/* Start of free space - round up to next sector; circular */
|
||||
mdac->rlocn.offset =
|
||||
((rlocn->offset + rlocn->size +
|
||||
(SECTOR_SIZE - rlocn->size % SECTOR_SIZE) -
|
||||
MDA_HEADER_SIZE) % (mdah->size - MDA_HEADER_SIZE))
|
||||
+ MDA_HEADER_SIZE;
|
||||
} else {
|
||||
/* Find an empty slot */
|
||||
/* FIXME Assume only one VG per mdah for now */
|
||||
mdac->rlocn.offset = MDA_HEADER_SIZE;
|
||||
}
|
||||
rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0);
|
||||
mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah);
|
||||
|
||||
if (!(mdac->rlocn.size = text_vg_export_raw(vg, "", buf, sizeof(buf)))) {
|
||||
if (!(mdac->rlocn.size = text_vg_export_raw(vg, "", &buf))) {
|
||||
log_error("VG %s metadata writing failed", vg->name);
|
||||
goto out;
|
||||
}
|
||||
@@ -414,24 +431,26 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
if (!r && !dev_close(mdac->area.dev))
|
||||
stack;
|
||||
|
||||
if (buf)
|
||||
dbg_free(buf);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
static int _vg_commit_raw_rlocn(struct format_instance *fid,
|
||||
struct volume_group *vg,
|
||||
struct metadata_area *mda,
|
||||
int precommit)
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct mda_header *mdah;
|
||||
struct raw_locn *rlocn;
|
||||
struct physical_volume *pv;
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
int r = 0;
|
||||
int found = 0;
|
||||
|
||||
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
if (pv->dev == mdac->area.dev) {
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (pvl->pv->dev == mdac->area.dev) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
@@ -445,18 +464,23 @@ static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
|
||||
rlocn = &mdah->raw_locns[0];
|
||||
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0))) {
|
||||
mdah->raw_locns[0].offset = 0;
|
||||
mdah->raw_locns[1].offset = 0;
|
||||
mdah->raw_locns[2].offset = 0;
|
||||
rlocn = &mdah->raw_locns[0];
|
||||
}
|
||||
|
||||
if (precommit)
|
||||
rlocn++;
|
||||
|
||||
rlocn->offset = mdac->rlocn.offset;
|
||||
rlocn->size = mdac->rlocn.size;
|
||||
rlocn->checksum = mdac->rlocn.checksum;
|
||||
|
||||
log_debug("Committing %s metadata (%u) to %s header at %" PRIu64,
|
||||
vg->name, vg->seqno, dev_name(mdac->area.dev),
|
||||
mdac->area.start);
|
||||
log_debug("%sCommitting %s metadata (%u) to %s header at %" PRIu64,
|
||||
precommit ? "Pre-" : "", vg->name, vg->seqno,
|
||||
dev_name(mdac->area.dev), mdac->area.start);
|
||||
if (!_raw_write_mda_header(fid->fmt, mdac->area.dev, mdac->area.start,
|
||||
mdah)) {
|
||||
log_error("Failed to write metadata area header");
|
||||
@@ -466,25 +490,36 @@ static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
if (!dev_close(mdac->area.dev))
|
||||
if (!precommit && !dev_close(mdac->area.dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
return _vg_commit_raw_rlocn(fid, vg, mda, 0);
|
||||
}
|
||||
|
||||
static int _vg_precommit_raw(struct format_instance *fid,
|
||||
struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
return _vg_commit_raw_rlocn(fid, vg, mda, 1);
|
||||
}
|
||||
|
||||
/* Close metadata area devices */
|
||||
static int _vg_revert_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct physical_volume *pv;
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
int found = 0;
|
||||
|
||||
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
if (pv->dev == mdac->area.dev) {
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (pvl->pv->dev == mdac->area.dev) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
@@ -517,7 +552,7 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
|
||||
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0))) {
|
||||
rlocn = &mdah->raw_locns[0];
|
||||
mdah->raw_locns[1].offset = 0;
|
||||
}
|
||||
@@ -543,13 +578,13 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
|
||||
static struct volume_group *_vg_read_file_name(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
const char *path_live)
|
||||
const char *read_path)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
time_t when;
|
||||
char *desc;
|
||||
|
||||
if (!(vg = text_vg_import_file(fid, path_live, &when, &desc))) {
|
||||
if (!(vg = text_vg_import_file(fid, read_path, &when, &desc))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
@@ -562,10 +597,10 @@ static struct volume_group *_vg_read_file_name(struct format_instance *fid,
|
||||
if (vgname && strcmp(vgname, vg->name)) {
|
||||
pool_free(fid->fmt->cmd->mem, vg);
|
||||
log_err("'%s' does not contain volume group '%s'.",
|
||||
path_live, vgname);
|
||||
read_path, vgname);
|
||||
return NULL;
|
||||
} else
|
||||
log_debug("Read volume group %s from %s", vg->name, path_live);
|
||||
log_debug("Read volume group %s from %s", vg->name, read_path);
|
||||
|
||||
return vg;
|
||||
}
|
||||
@@ -579,6 +614,15 @@ static struct volume_group *_vg_read_file(struct format_instance *fid,
|
||||
return _vg_read_file_name(fid, vgname, tc->path_live);
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read_precommit_file(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct text_context *tc = (struct text_context *) mda->metadata_locn;
|
||||
|
||||
return _vg_read_file_name(fid, vgname, tc->path_edit);
|
||||
}
|
||||
|
||||
static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
@@ -734,7 +778,7 @@ static int _scan_file(const struct format_type *fmt)
|
||||
{
|
||||
struct dirent *dirent;
|
||||
struct dir_list *dl;
|
||||
struct list *dlh, *dir_list;
|
||||
struct list *dir_list;
|
||||
char *tmp;
|
||||
DIR *d;
|
||||
struct volume_group *vg;
|
||||
@@ -744,8 +788,7 @@ static int _scan_file(const struct format_type *fmt)
|
||||
|
||||
dir_list = &((struct mda_lists *) fmt->private)->dirs;
|
||||
|
||||
list_iterate(dlh, dir_list) {
|
||||
dl = list_item(dlh, struct dir_list);
|
||||
list_iterate_items(dl, dir_list) {
|
||||
if (!(d = opendir(dl->dir))) {
|
||||
log_sys_error("opendir", dl->dir);
|
||||
continue;
|
||||
@@ -833,7 +876,7 @@ int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area,
|
||||
static int _scan_raw(const struct format_type *fmt)
|
||||
{
|
||||
struct raw_list *rl;
|
||||
struct list *rlh, *raw_list;
|
||||
struct list *raw_list;
|
||||
char vgnamebuf[NAME_LEN + 2];
|
||||
struct volume_group *vg;
|
||||
struct format_instance fid;
|
||||
@@ -843,14 +886,12 @@ static int _scan_raw(const struct format_type *fmt)
|
||||
fid.fmt = fmt;
|
||||
list_init(&fid.metadata_areas);
|
||||
|
||||
list_iterate(rlh, raw_list) {
|
||||
rl = list_item(rlh, struct raw_list);
|
||||
|
||||
list_iterate_items(rl, raw_list) {
|
||||
/* FIXME We're reading mdah twice here... */
|
||||
if (vgname_from_mda(fmt, &rl->dev_area, vgnamebuf,
|
||||
sizeof(vgnamebuf))) {
|
||||
if ((vg = _vg_read_raw_area(&fid, vgnamebuf,
|
||||
&rl->dev_area)))
|
||||
&rl->dev_area, 0)))
|
||||
lvmcache_update_vg(vg);
|
||||
}
|
||||
}
|
||||
@@ -875,6 +916,7 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
uint64_t start1, mda_size1; /* First area - start of disk */
|
||||
uint64_t start2, mda_size2; /* Second area - end of disk */
|
||||
uint64_t wipe_size = 8 << SECTOR_SHIFT;
|
||||
size_t pagesize = getpagesize();
|
||||
|
||||
if (!pvmetadatacopies) {
|
||||
/* Space available for PEs */
|
||||
@@ -902,10 +944,21 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
/* Place mda straight after label area at start of disk */
|
||||
start1 = LABEL_SCAN_SIZE;
|
||||
|
||||
/* Unless the space available is tiny, round to PAGE_SIZE boundary */
|
||||
if ((!pe_start && !pe_end) ||
|
||||
((pe_start > start1) && (pe_start - start1 >= MDA_SIZE_MIN))) {
|
||||
mda_adjustment = start1 % pagesize;
|
||||
if (mda_adjustment) {
|
||||
start1 += (pagesize - mda_adjustment);
|
||||
pv->size -= ((pagesize - mda_adjustment) >>
|
||||
SECTOR_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure it's not going to be bigger than the disk! */
|
||||
if (mda_size1 > disk_size) {
|
||||
log_print("Warning: metadata area fills disk %s",
|
||||
dev_name(pv->dev));
|
||||
if (start1 + mda_size1 > disk_size) {
|
||||
log_print("Warning: metadata area fills disk leaving no "
|
||||
"space for data on %s.", dev_name(pv->dev));
|
||||
/* Leave some free space for rounding */
|
||||
/* Avoid empty data area as could cause tools problems */
|
||||
mda_size1 = disk_size - start1 - alignment * 2;
|
||||
@@ -998,7 +1051,6 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
struct label *label;
|
||||
struct lvmcache_info *info;
|
||||
struct mda_context *mdac;
|
||||
struct list *mdash;
|
||||
struct metadata_area *mda;
|
||||
char buf[MDA_HEADER_SIZE];
|
||||
struct mda_header *mdah = (struct mda_header *) buf;
|
||||
@@ -1026,8 +1078,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
del_mdas(&info->mdas);
|
||||
else
|
||||
list_init(&info->mdas);
|
||||
list_iterate(mdash, mdas) {
|
||||
mda = list_item(mdash, struct metadata_area);
|
||||
list_iterate_items(mda, mdas) {
|
||||
mdac = mda->metadata_locn;
|
||||
log_debug("Creating metadata area on %s at sector %"
|
||||
PRIu64 " size %" PRIu64 " sectors",
|
||||
@@ -1050,8 +1101,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
/* Set pe_start to first aligned sector after any metadata
|
||||
* areas that begin before pe_start */
|
||||
pv->pe_start = PE_ALIGN;
|
||||
list_iterate(mdash, &info->mdas) {
|
||||
mda = list_item(mdash, struct metadata_area);
|
||||
list_iterate_items(mda, &info->mdas) {
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
if (pv->dev == mdac->area.dev &&
|
||||
(mdac->area.start < (pv->pe_start << SECTOR_SHIFT)) &&
|
||||
@@ -1075,8 +1125,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(mdash, &info->mdas) {
|
||||
mda = list_item(mdash, struct metadata_area);
|
||||
list_iterate_items(mda, &info->mdas) {
|
||||
mdac = mda->metadata_locn;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
mdah->size = mdac->area.size;
|
||||
@@ -1099,45 +1148,16 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get_pv_from_vg(const struct format_type *fmt, const char *vg_name,
|
||||
const char *id, struct physical_volume *pv)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
int consistent = 0;
|
||||
|
||||
if (!(vg = vg_read(fmt->cmd, vg_name, &consistent))) {
|
||||
log_error("format_text: _vg_read failed to read VG %s",
|
||||
vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!consistent)
|
||||
log_error("Warning: Volume group %s is not consistent",
|
||||
vg_name);
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
if (id_equal(&pvl->pv->id, (const struct id *) id)) {
|
||||
memcpy(pv, pvl->pv, sizeof(*pv));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _add_raw(struct list *raw_list, struct device_area *dev_area)
|
||||
{
|
||||
struct raw_list *rl;
|
||||
struct list *rlh;
|
||||
|
||||
/* Already present? */
|
||||
list_iterate(rlh, raw_list) {
|
||||
rl = list_item(rlh, struct raw_list);
|
||||
list_iterate_items(rl, raw_list) {
|
||||
/* FIXME Check size/overlap consistency too */
|
||||
if (rl->dev_area.dev == dev_area->dev &&
|
||||
rl->dev_area.start == dev_area->start) return 1;
|
||||
rl->dev_area.start == dev_area->start)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(rl = dbg_malloc(sizeof(struct raw_list)))) {
|
||||
@@ -1158,7 +1178,6 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
struct lvmcache_info *info;
|
||||
struct metadata_area *mda, *mda_new;
|
||||
struct mda_context *mdac, *mdac_new;
|
||||
struct list *mdah, *dah;
|
||||
struct data_area_list *da;
|
||||
|
||||
if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) {
|
||||
@@ -1175,19 +1194,19 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
|
||||
/* Have we already cached vgname? */
|
||||
if (info->vginfo && info->vginfo->vgname && *info->vginfo->vgname &&
|
||||
_get_pv_from_vg(info->fmt, info->vginfo->vgname, info->dev->pvid,
|
||||
pv)) {
|
||||
get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
|
||||
info->dev->pvid, pv)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Perform full scan and try again */
|
||||
if (!memlock()) {
|
||||
lvmcache_label_scan(fmt->cmd, 1);
|
||||
/* Perform full scan (just the first time) and try again */
|
||||
if (!memlock() && !full_scan_done()) {
|
||||
lvmcache_label_scan(fmt->cmd, 2);
|
||||
|
||||
if (info->vginfo && info->vginfo->vgname &&
|
||||
*info->vginfo->vgname &&
|
||||
_get_pv_from_vg(info->fmt, info->vginfo->vgname,
|
||||
info->dev->pvid, pv)) {
|
||||
get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
|
||||
info->dev->pvid, pv)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -1205,17 +1224,15 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
list_size(&info->das), dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
list_iterate(dah, &info->das) {
|
||||
da = list_item(dah, struct data_area_list);
|
||||
|
||||
list_iterate_items(da, &info->das)
|
||||
pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT;
|
||||
}
|
||||
|
||||
if (!mdas)
|
||||
return 1;
|
||||
|
||||
/* Add copy of mdas to supplied list */
|
||||
list_iterate(mdah, &info->mdas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &info->mdas) {
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
if (!(mda_new = pool_alloc(fmt->cmd->mem, sizeof(*mda_new)))) {
|
||||
log_error("metadata_area allocation failed");
|
||||
@@ -1272,6 +1289,7 @@ static void _destroy(const struct format_type *fmt)
|
||||
|
||||
static struct metadata_area_ops _metadata_text_file_ops = {
|
||||
vg_read:_vg_read_file,
|
||||
vg_read_precommit:_vg_read_precommit_file,
|
||||
vg_write:_vg_write_file,
|
||||
vg_remove:_vg_remove_file,
|
||||
vg_commit:_vg_commit_file
|
||||
@@ -1286,8 +1304,10 @@ static struct metadata_area_ops _metadata_text_file_backup_ops = {
|
||||
|
||||
static struct metadata_area_ops _metadata_text_raw_ops = {
|
||||
vg_read:_vg_read_raw,
|
||||
vg_read_precommit:_vg_read_precommit_raw,
|
||||
vg_write:_vg_write_raw,
|
||||
vg_remove:_vg_remove_raw,
|
||||
vg_precommit:_vg_precommit_raw,
|
||||
vg_commit:_vg_commit_raw,
|
||||
vg_revert:_vg_revert_raw
|
||||
};
|
||||
@@ -1302,7 +1322,7 @@ static int _pv_setup(const struct format_type *fmt,
|
||||
{
|
||||
struct metadata_area *mda, *mda_new, *mda2;
|
||||
struct mda_context *mdac, *mdac_new, *mdac2;
|
||||
struct list *pvmdas, *pvmdash, *mdash;
|
||||
struct list *pvmdas;
|
||||
struct lvmcache_info *info;
|
||||
int found;
|
||||
uint64_t pe_end = 0;
|
||||
@@ -1317,8 +1337,7 @@ static int _pv_setup(const struct format_type *fmt,
|
||||
/* Iterate through all mdas on this PV */
|
||||
if ((info = info_from_pvid(pv->dev->pvid))) {
|
||||
pvmdas = &info->mdas;
|
||||
list_iterate(pvmdash, pvmdas) {
|
||||
mda = list_item(pvmdash, struct metadata_area);
|
||||
list_iterate_items(mda, pvmdas) {
|
||||
mdac =
|
||||
(struct mda_context *) mda->metadata_locn;
|
||||
|
||||
@@ -1326,10 +1345,7 @@ static int _pv_setup(const struct format_type *fmt,
|
||||
|
||||
/* Ensure it isn't already on list */
|
||||
found = 0;
|
||||
list_iterate(mdash, mdas) {
|
||||
mda2 =
|
||||
list_item(mdash,
|
||||
struct metadata_area);
|
||||
list_iterate_items(mda2, mdas) {
|
||||
if (mda2->ops !=
|
||||
&_metadata_text_raw_ops) continue;
|
||||
mdac2 =
|
||||
@@ -1391,9 +1407,10 @@ static struct format_instance *_create_text_instance(const struct format_type
|
||||
struct mda_context *mdac, *mdac_new;
|
||||
struct dir_list *dl;
|
||||
struct raw_list *rl;
|
||||
struct list *dlh, *dir_list, *rlh, *raw_list, *mdas, *mdash, *infoh;
|
||||
struct list *dir_list, *raw_list, *mdas;
|
||||
char path[PATH_MAX];
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_info *info;
|
||||
|
||||
if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
|
||||
log_error("Couldn't allocate format instance object.");
|
||||
@@ -1415,8 +1432,7 @@ static struct format_instance *_create_text_instance(const struct format_type
|
||||
} else {
|
||||
dir_list = &((struct mda_lists *) fmt->private)->dirs;
|
||||
|
||||
list_iterate(dlh, dir_list) {
|
||||
dl = list_item(dlh, struct dir_list);
|
||||
list_iterate_items(dl, dir_list) {
|
||||
if (lvm_snprintf(path, PATH_MAX, "%s/%s",
|
||||
dl->dir, vgname) < 0) {
|
||||
log_error("Name too long %s/%s", dl->dir,
|
||||
@@ -1436,9 +1452,7 @@ static struct format_instance *_create_text_instance(const struct format_type
|
||||
|
||||
raw_list = &((struct mda_lists *) fmt->private)->raws;
|
||||
|
||||
list_iterate(rlh, raw_list) {
|
||||
rl = list_item(rlh, struct raw_list);
|
||||
|
||||
list_iterate_items(rl, raw_list) {
|
||||
/* FIXME Cache this; rescan below if some missing */
|
||||
if (!_raw_holds_vgname(fid, &rl->dev_area, vgname))
|
||||
continue;
|
||||
@@ -1466,10 +1480,9 @@ static struct format_instance *_create_text_instance(const struct format_type
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
list_iterate(infoh, &vginfo->infos) {
|
||||
mdas = &(list_item(infoh, struct lvmcache_info)->mdas);
|
||||
list_iterate(mdash, mdas) {
|
||||
mda = list_item(mdash, struct metadata_area);
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
mdas = &info->mdas;
|
||||
list_iterate_items(mda, mdas) {
|
||||
mdac =
|
||||
(struct mda_context *) mda->metadata_locn;
|
||||
|
||||
@@ -1643,7 +1656,8 @@ struct format_type *create_text_format(struct cmd_context *cmd)
|
||||
fmt->ops = &_text_handler;
|
||||
fmt->name = FMT_TEXT_NAME;
|
||||
fmt->alias = FMT_TEXT_ALIAS;
|
||||
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_UNLIMITED_VOLS;
|
||||
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_PRECOMMIT |
|
||||
FMT_UNLIMITED_VOLS;
|
||||
|
||||
if (!(mda_lists = dbg_malloc(sizeof(struct mda_lists)))) {
|
||||
log_error("Failed to allocate dir_list");
|
||||
|
||||
@@ -59,8 +59,7 @@ int print_tags(struct list *tags, char *buffer, size_t size);
|
||||
int read_tags(struct pool *mem, struct list *tags, struct config_value *cv);
|
||||
|
||||
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
|
||||
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||
uint32_t size);
|
||||
int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
|
||||
struct volume_group *text_vg_import_file(struct format_instance *fid,
|
||||
const char *file,
|
||||
time_t *when, char **desc);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "toolcontext.h"
|
||||
#include "lvmcache.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "pv_alloc.h"
|
||||
#include "segtype.h"
|
||||
#include "text_import.h"
|
||||
|
||||
@@ -31,7 +32,7 @@ typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
|
||||
struct hash_table * pv_hash);
|
||||
|
||||
#define _read_int32(root, path, result) \
|
||||
get_config_uint32(root, path, result)
|
||||
get_config_uint32(root, path, (uint32_t *) result)
|
||||
|
||||
#define _read_uint32(root, path, result) \
|
||||
get_config_uint32(root, path, result)
|
||||
@@ -190,6 +191,7 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
|
||||
}
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
|
||||
/* Optional tags */
|
||||
if ((cn = find_config_node(pvn, "tags")) &&
|
||||
@@ -208,6 +210,11 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
|
||||
pv->pe_alloc_count = 0;
|
||||
pv->fmt = fid->fmt;
|
||||
|
||||
if (!alloc_pv_segment_whole_pv(mem, pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
vg->pv_count++;
|
||||
list_add(&vg->pvs, &pvl->list);
|
||||
|
||||
@@ -216,12 +223,9 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
|
||||
|
||||
static void _insert_segment(struct logical_volume *lv, struct lv_segment *seg)
|
||||
{
|
||||
struct list *segh;
|
||||
struct lv_segment *comp;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
comp = list_item(segh, struct lv_segment);
|
||||
|
||||
list_iterate_items(comp, &lv->segments) {
|
||||
if (comp->le > seg->le) {
|
||||
list_add(&comp->list, &seg->list);
|
||||
return;
|
||||
@@ -283,19 +287,13 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(seg = alloc_lv_segment(mem, area_count))) {
|
||||
if (!(seg = alloc_lv_segment(mem, segtype, lv, start_extent,
|
||||
extent_count, 0, 0, NULL, area_count,
|
||||
extent_count, 0, 0, 0))) {
|
||||
log_error("Segment allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->lv = lv;
|
||||
seg->le = start_extent;
|
||||
seg->len = extent_count;
|
||||
seg->area_len = extent_count;
|
||||
seg->status = 0u;
|
||||
seg->segtype = segtype;
|
||||
seg->extents_copied = 0u;
|
||||
|
||||
if (seg->segtype->ops->text_import &&
|
||||
!seg->segtype->ops->text_import(seg, sn, pv_hash)) {
|
||||
stack;
|
||||
@@ -315,17 +313,18 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
|
||||
*/
|
||||
_insert_segment(lv, seg);
|
||||
|
||||
if (seg->segtype->flags & SEG_AREAS_MIRRORED)
|
||||
if (seg_is_mirrored(seg))
|
||||
lv->status |= MIRRORED;
|
||||
|
||||
if (seg->segtype->flags & SEG_VIRTUAL)
|
||||
if (seg_is_virtual(seg))
|
||||
lv->status |= VIRTUAL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
|
||||
const struct config_node *cn, struct hash_table *pv_hash)
|
||||
const struct config_node *cn, struct hash_table *pv_hash,
|
||||
uint32_t flags)
|
||||
{
|
||||
unsigned int s;
|
||||
struct config_value *cv;
|
||||
@@ -361,19 +360,17 @@ int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
|
||||
|
||||
/* FIXME Cope if LV not yet read in */
|
||||
if ((pv = hash_lookup(pv_hash, cv->v.str))) {
|
||||
seg->area[s].type = AREA_PV;
|
||||
seg->area[s].u.pv.pv = pv;
|
||||
seg->area[s].u.pv.pe = cv->next->v.i;
|
||||
if (!set_lv_segment_area_pv(seg, s, pv, cv->next->v.i)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Adjust extent counts in the pv and vg.
|
||||
*/
|
||||
pv->pe_alloc_count += seg->area_len;
|
||||
seg->lv->vg->free_count -= seg->area_len;
|
||||
|
||||
} else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) {
|
||||
seg->area[s].type = AREA_LV;
|
||||
seg->area[s].u.lv.lv = lv1;
|
||||
seg->area[s].u.lv.le = cv->next->v.i;
|
||||
set_lv_segment_area_lv(seg, s, lv1, cv->next->v.i,
|
||||
flags);
|
||||
} else {
|
||||
log_error("Couldn't find volume '%s' "
|
||||
"for segment '%s'.",
|
||||
@@ -437,7 +434,7 @@ static int _read_segments(struct pool *mem, struct volume_group *vg,
|
||||
/*
|
||||
* Check there are no gaps or overlaps in the lv.
|
||||
*/
|
||||
if (!lv_check_segments(lv)) {
|
||||
if (!check_lv_segments(lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -508,6 +505,8 @@ static int _read_lvnames(struct format_instance *fid, struct pool *mem,
|
||||
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead))
|
||||
lv->read_ahead = 0;
|
||||
|
||||
lv->snapshot = NULL;
|
||||
list_init(&lv->snapshot_segs);
|
||||
list_init(&lv->segments);
|
||||
list_init(&lv->tags);
|
||||
|
||||
@@ -561,24 +560,29 @@ static int _read_lvsegs(struct format_instance *fid, struct pool *mem,
|
||||
|
||||
lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
|
||||
|
||||
/* Skip this for now for snapshots */
|
||||
if (!(lv->status & SNAPSHOT)) {
|
||||
lv->minor = -1;
|
||||
if ((lv->status & FIXED_MINOR) &&
|
||||
!_read_int32(lvn, "minor", &lv->minor)) {
|
||||
log_error("Couldn't read minor number for logical "
|
||||
"volume %s.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
lv->major = -1;
|
||||
if ((lv->status & FIXED_MINOR) &&
|
||||
!_read_int32(lvn, "major", &lv->major)) {
|
||||
log_error("Couldn't read major number for logical "
|
||||
"volume %s.", lv->name);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* FIXME We now have 2 LVs for each snapshot. The real one was
|
||||
* created by vg_add_snapshot from the segment text_import.
|
||||
*/
|
||||
if (lv->status & SNAPSHOT) {
|
||||
vg->lv_count--;
|
||||
list_del(&lvl->list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lv->minor = -1;
|
||||
if ((lv->status & FIXED_MINOR) &&
|
||||
!_read_int32(lvn, "minor", &lv->minor)) {
|
||||
log_error("Couldn't read minor number for logical "
|
||||
"volume %s.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->major = -1;
|
||||
if ((lv->status & FIXED_MINOR) &&
|
||||
!_read_int32(lvn, "major", &lv->major)) {
|
||||
log_error("Couldn't read major number for logical "
|
||||
"volume %s.", lv->name);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -736,7 +740,6 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
}
|
||||
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
list_init(&vg->tags);
|
||||
|
||||
/* Optional tags */
|
||||
|
||||
@@ -81,5 +81,6 @@ struct mda_context {
|
||||
#define FMTT_VERSION 1
|
||||
#define MDA_HEADER_SIZE 512
|
||||
#define LVM2_LABEL "LVM2 001"
|
||||
#define MDA_SIZE_MIN (8 * getpagesize())
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#define _LVM_TEXT_EXPORT_H
|
||||
|
||||
#define outf(args...) do {if (!out_text(args)) {stack; return 0;}} while (0)
|
||||
#define outnl(f) do {if (!f->nl(f)) {stack; return 0;}} while (0)
|
||||
|
||||
struct formatter;
|
||||
struct lv_segment;
|
||||
|
||||
@@ -20,6 +20,7 @@ struct lv_segment;
|
||||
struct config_node;
|
||||
|
||||
int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
|
||||
const struct config_node *cn, struct hash_table *pv_hash);
|
||||
const struct config_node *cn, struct hash_table *pv_hash,
|
||||
uint32_t flags);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -39,7 +39,6 @@ static int _write(struct label *label, char *buf)
|
||||
struct pv_header *pvhdr;
|
||||
struct lvmcache_info *info;
|
||||
struct disk_locn *pvh_dlocn_xl;
|
||||
struct list *mdash, *dash;
|
||||
struct metadata_area *mda;
|
||||
struct mda_context *mdac;
|
||||
struct data_area_list *da;
|
||||
@@ -57,9 +56,7 @@ static int _write(struct label *label, char *buf)
|
||||
pvh_dlocn_xl = &pvhdr->disk_areas_xl[0];
|
||||
|
||||
/* List of data areas (holding PEs) */
|
||||
list_iterate(dash, &info->das) {
|
||||
da = list_item(dash, struct data_area_list);
|
||||
|
||||
list_iterate_items(da, &info->das) {
|
||||
pvh_dlocn_xl->offset = xlate64(da->disk_locn.offset);
|
||||
pvh_dlocn_xl->size = xlate64(da->disk_locn.size);
|
||||
pvh_dlocn_xl++;
|
||||
@@ -71,8 +68,7 @@ static int _write(struct label *label, char *buf)
|
||||
pvh_dlocn_xl++;
|
||||
|
||||
/* List of metadata area header locations */
|
||||
list_iterate(mdash, &info->mdas) {
|
||||
mda = list_item(mdash, struct metadata_area);
|
||||
list_iterate_items(mda, &info->mdas) {
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
|
||||
if (mdac->area.dev != info->dev)
|
||||
@@ -198,7 +194,6 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
struct lvmcache_info *info;
|
||||
struct disk_locn *dlocn_xl;
|
||||
uint64_t offset;
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
char vgnamebuf[NAME_LEN + 2];
|
||||
struct mda_context *mdac;
|
||||
@@ -235,8 +230,7 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
dlocn_xl++;
|
||||
}
|
||||
|
||||
list_iterate(mdah, &info->mdas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &info->mdas) {
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
if (vgname_from_mda(info->fmt, &mdac->area, vgnamebuf,
|
||||
sizeof(vgnamebuf))) {
|
||||
|
||||
@@ -98,14 +98,11 @@ int label_register_handler(const char *name, struct labeller *handler)
|
||||
|
||||
struct labeller *label_get_handler(const char *name)
|
||||
{
|
||||
struct list *lih;
|
||||
struct labeller_i *li;
|
||||
|
||||
list_iterate(lih, &_labellers) {
|
||||
li = list_item(lih, struct labeller_i);
|
||||
list_iterate_items(li, &_labellers)
|
||||
if (!strcmp(li->name, name))
|
||||
return li->l;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -113,16 +110,20 @@ struct labeller *label_get_handler(const char *name)
|
||||
static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
uint64_t *label_sector)
|
||||
{
|
||||
struct list *lih;
|
||||
struct labeller_i *li;
|
||||
struct labeller *r = NULL;
|
||||
struct label_header *lh;
|
||||
struct lvmcache_info *info;
|
||||
uint64_t sector;
|
||||
int found = 0;
|
||||
char readbuf[LABEL_SCAN_SIZE];
|
||||
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
|
||||
if ((info = info_from_pvid(dev->pvid)))
|
||||
lvmcache_update_vgname(info, ORPHAN);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -161,8 +162,7 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
continue;
|
||||
}
|
||||
|
||||
list_iterate(lih, &_labellers) {
|
||||
li = list_item(lih, struct labeller_i);
|
||||
list_iterate_items(li, &_labellers) {
|
||||
if (li->l->ops->can_handle(li->l, (char *) lh, sector)) {
|
||||
log_very_verbose("%s: %s label detected",
|
||||
dev_name(dev), li->name);
|
||||
@@ -182,10 +182,13 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
log_very_verbose("%s: No label detected", dev_name(dev));
|
||||
|
||||
out:
|
||||
if (!found) {
|
||||
if ((info = info_from_pvid(dev->pvid)))
|
||||
lvmcache_update_vgname(info, ORPHAN);
|
||||
log_very_verbose("%s: No label detected", dev_name(dev));
|
||||
}
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
@@ -200,7 +203,6 @@ int label_remove(struct device *dev)
|
||||
int r = 1;
|
||||
uint64_t sector;
|
||||
int wipe;
|
||||
struct list *lih;
|
||||
struct labeller_i *li;
|
||||
struct label_header *lh;
|
||||
|
||||
@@ -236,8 +238,7 @@ int label_remove(struct device *dev)
|
||||
if (xlate64(lh->sector_xl) == sector)
|
||||
wipe = 1;
|
||||
} else {
|
||||
list_iterate(lih, &_labellers) {
|
||||
li = list_item(lih, struct labeller_i);
|
||||
list_iterate_items(li, &_labellers) {
|
||||
if (li->l->ops->can_handle(li->l, (char *) lh,
|
||||
sector)) {
|
||||
wipe = 1;
|
||||
@@ -279,7 +280,7 @@ int label_read(struct device *dev, struct label **result)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((r = l->ops->read(l, dev, buf, result)) && result && *result)
|
||||
if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result)
|
||||
(*result)->sector = sector;
|
||||
|
||||
return r;
|
||||
@@ -309,7 +310,7 @@ int label_write(struct device *dev, struct label *label)
|
||||
lh->sector_xl = xlate64(label->sector);
|
||||
lh->offset_xl = xlate32(sizeof(*lh));
|
||||
|
||||
if (!label->labeller->ops->write(label, buf)) {
|
||||
if (!(label->labeller->ops->write)(label, buf)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -147,10 +147,16 @@ static int _send_request(char *inbuf, int inlen, char **retbuf)
|
||||
}
|
||||
|
||||
/* Was it an error ? */
|
||||
if (outheader->status < 0) {
|
||||
errno = -outheader->status;
|
||||
log_error("cluster request failed: %s", strerror(errno));
|
||||
return 0;
|
||||
if (outheader->status != 0) {
|
||||
errno = outheader->status;
|
||||
|
||||
/* Only return an error here if there are no node-specific
|
||||
errors present in the message that might have more detail */
|
||||
if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
|
||||
log_error("cluster request failed: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -328,7 +334,7 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
|
||||
* VG locks are just that: locks, and have no side effects
|
||||
* so we only need to do them on the local node because all
|
||||
* locks are cluster-wide.
|
||||
* Also, if the lock is exclusive it makes no sense to try to
|
||||
* Also, if the lock is exclusive it makes no sense to try to
|
||||
* acquire it on all nodes, so just do that on the local node too.
|
||||
*/
|
||||
if (cmd == CLVMD_CMD_LOCK_VG ||
|
||||
@@ -341,10 +347,11 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
|
||||
|
||||
/* If any nodes were down then display them and return an error */
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status == -EHOSTDOWN) {
|
||||
if (response[i].status == EHOSTDOWN) {
|
||||
log_error("clvmd not running on node %s",
|
||||
response[i].node);
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
} else if (response[i].status) {
|
||||
log_error("Error locking on node %s: %s",
|
||||
response[i].node,
|
||||
@@ -352,6 +359,7 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
|
||||
response[i].response :
|
||||
strerror(response[i].status));
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,7 +446,7 @@ int init_cluster_locking(struct locking_type *locking, struct config_tree *cft)
|
||||
locking->lock_resource = _lock_resource;
|
||||
locking->fin_locking = _locking_end;
|
||||
locking->reset_locking = _reset_locking;
|
||||
locking->flags = LCK_PRE_MEMLOCK;
|
||||
locking->flags = LCK_PRE_MEMLOCK | LCK_CLUSTERED;
|
||||
|
||||
_clvmd_sock = _open_local_sock();
|
||||
if (_clvmd_sock == -1)
|
||||
@@ -455,6 +463,7 @@ int locking_init(int type, struct config_tree *cf, uint32_t *flags)
|
||||
|
||||
/* Ask LVM to lock memory before calling us */
|
||||
*flags |= LCK_PRE_MEMLOCK;
|
||||
*flags |= LCK_CLUSTERED;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ static char _lock_dir[NAME_LEN];
|
||||
|
||||
static sig_t _oldhandler;
|
||||
static sigset_t _fullsigset, _intsigset;
|
||||
static int _handler_installed;
|
||||
static volatile sig_atomic_t _handler_installed;
|
||||
|
||||
static int _release_lock(const char *file, int unlock)
|
||||
{
|
||||
@@ -95,38 +95,40 @@ static void _reset_file_locking(void)
|
||||
static void _remove_ctrl_c_handler()
|
||||
{
|
||||
siginterrupt(SIGINT, 0);
|
||||
if (!_handler_installed || _oldhandler == SIG_ERR)
|
||||
if (!_handler_installed)
|
||||
return;
|
||||
|
||||
_handler_installed = 0;
|
||||
|
||||
sigprocmask(SIG_SETMASK, &_fullsigset, NULL);
|
||||
if (signal(SIGINT, _oldhandler) == SIG_ERR)
|
||||
log_sys_error("signal", "_remove_ctrl_c_handler");
|
||||
|
||||
_handler_installed = 0;
|
||||
}
|
||||
|
||||
static void _trap_ctrl_c(int sig)
|
||||
{
|
||||
_remove_ctrl_c_handler();
|
||||
log_error("CTRL-c detected: giving up waiting for lock");
|
||||
return;
|
||||
}
|
||||
|
||||
static void _install_ctrl_c_handler()
|
||||
{
|
||||
if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR)
|
||||
_handler_installed = 1;
|
||||
|
||||
if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR) {
|
||||
_handler_installed = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
sigprocmask(SIG_SETMASK, &_intsigset, NULL);
|
||||
siginterrupt(SIGINT, 1);
|
||||
|
||||
_handler_installed = 1;
|
||||
}
|
||||
|
||||
static int _lock_file(const char *file, int flags)
|
||||
{
|
||||
int operation;
|
||||
int r = 1;
|
||||
int old_errno;
|
||||
|
||||
struct lock_list *ll;
|
||||
struct stat buf1, buf2;
|
||||
@@ -176,10 +178,12 @@ static int _lock_file(const char *file, int flags)
|
||||
_install_ctrl_c_handler();
|
||||
|
||||
r = flock(ll->lf, operation);
|
||||
old_errno = errno;
|
||||
if (!(flags & LCK_NONBLOCK))
|
||||
_remove_ctrl_c_handler();
|
||||
|
||||
if (r) {
|
||||
errno = old_errno;
|
||||
log_sys_error("flock", ll->res);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -124,6 +124,8 @@ static inline void _update_vg_lock_count(int flags)
|
||||
*/
|
||||
int init_locking(int type, struct config_tree *cft)
|
||||
{
|
||||
init_lockingfailed(0);
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
init_no_locking(&_locking, cft);
|
||||
@@ -165,6 +167,7 @@ int init_locking(int type, struct config_tree *cft)
|
||||
log_verbose("Locking disabled - only read operations permitted.");
|
||||
|
||||
init_no_locking(&_locking, cft);
|
||||
init_lockingfailed(1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -262,13 +265,10 @@ int lock_vol(struct cmd_context *cmd, const char *vol, int flags)
|
||||
/* Unlock list of LVs */
|
||||
int resume_lvs(struct cmd_context *cmd, struct list *lvs)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
|
||||
list_iterate(lvh, lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
resume_lv(cmd, lv->lvid.s);
|
||||
}
|
||||
list_iterate_items(lvl, lvs)
|
||||
resume_lv(cmd, lvl->lv->lvid.s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -277,15 +277,14 @@ int resume_lvs(struct cmd_context *cmd, struct list *lvs)
|
||||
int suspend_lvs(struct cmd_context *cmd, struct list *lvs)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
|
||||
list_iterate(lvh, lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (!suspend_lv(cmd, lv->lvid.s)) {
|
||||
log_error("Failed to suspend %s", lv->name);
|
||||
list_uniterate(lvh, lvs, lvh) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
resume_lv(cmd, lv->lvid.s);
|
||||
list_iterate_items(lvl, lvs) {
|
||||
if (!suspend_lv(cmd, lvl->lv->lvid.s)) {
|
||||
log_error("Failed to suspend %s", lvl->lv->name);
|
||||
list_uniterate(lvh, lvs, &lvl->list) {
|
||||
lvl = list_item(lvh, struct lv_list);
|
||||
resume_lv(cmd, lvl->lv->lvid.s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -299,15 +298,14 @@ int suspend_lvs(struct cmd_context *cmd, struct list *lvs)
|
||||
int activate_lvs_excl(struct cmd_context *cmd, struct list *lvs)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
|
||||
list_iterate(lvh, lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (!activate_lv_excl(cmd, lv->lvid.s)) {
|
||||
log_error("Failed to activate %s", lv->name);
|
||||
list_uniterate(lvh, lvs, lvh) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
activate_lv(cmd, lv->lvid.s);
|
||||
list_iterate_items(lvl, lvs) {
|
||||
if (!activate_lv_excl(cmd, lvl->lv->lvid.s)) {
|
||||
log_error("Failed to activate %s", lvl->lv->name);
|
||||
list_uniterate(lvh, lvs, &lvl->list) {
|
||||
lvl = list_item(lvh, struct lv_list);
|
||||
activate_lv(cmd, lvl->lv->lvid.s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -321,3 +319,9 @@ int vg_write_lock_held(void)
|
||||
{
|
||||
return _vg_write_lock_held;
|
||||
}
|
||||
|
||||
int locking_is_clustered(void)
|
||||
{
|
||||
return (_locking.flags & LCK_CLUSTERED) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ int init_locking(int type, struct config_tree *cf);
|
||||
void fin_locking(void);
|
||||
void reset_locking(void);
|
||||
int vg_write_lock_held(void);
|
||||
int locking_is_clustered(void);
|
||||
|
||||
/*
|
||||
* LCK_VG:
|
||||
|
||||
@@ -23,6 +23,7 @@ typedef void (*fin_lock_fn) (void);
|
||||
typedef void (*reset_lock_fn) (void);
|
||||
|
||||
#define LCK_PRE_MEMLOCK 0x00000001 /* Is memlock() needed before calls? */
|
||||
#define LCK_CLUSTERED 0x00000002
|
||||
|
||||
struct locking_type {
|
||||
uint32_t flags;
|
||||
@@ -40,4 +41,5 @@ int init_no_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
int init_file_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
|
||||
int init_external_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
|
||||
int init_cluster_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
|
||||
@@ -30,6 +30,7 @@ static int _test = 0;
|
||||
static int _partial = 0;
|
||||
static int _md_filtering = 0;
|
||||
static int _pvmove = 0;
|
||||
static int _full_scan_done = 0; /* Restrict to one full scan during each cmd */
|
||||
static int _debug_level = 0;
|
||||
static int _syslog = 0;
|
||||
static int _log_to_file = 0;
|
||||
@@ -39,6 +40,7 @@ static int _indent = 1;
|
||||
static int _log_cmd_name = 0;
|
||||
static int _log_suppress = 0;
|
||||
static int _ignorelockingfailure = 0;
|
||||
static int _lockingfailed = 0;
|
||||
static int _security_level = SECURITY_LEVEL;
|
||||
static char _cmd_name[30] = "";
|
||||
static char _msg_prefix[30] = " ";
|
||||
@@ -70,7 +72,7 @@ void init_log_direct(const char *log_file, int append)
|
||||
{
|
||||
int open_flags = append ? 0 : O_TRUNC;
|
||||
|
||||
dev_create_file(log_file, &_log_dev, &_log_dev_alias);
|
||||
dev_create_file(log_file, &_log_dev, &_log_dev_alias, 1);
|
||||
if (!dev_open_flags(&_log_dev, O_RDWR | O_CREAT | open_flags, 1, 0))
|
||||
return;
|
||||
|
||||
@@ -149,11 +151,21 @@ void init_pvmove(int level)
|
||||
_pvmove = level;
|
||||
}
|
||||
|
||||
void init_full_scan_done(int level)
|
||||
{
|
||||
_full_scan_done = level;
|
||||
}
|
||||
|
||||
void init_ignorelockingfailure(int level)
|
||||
{
|
||||
_ignorelockingfailure = level;
|
||||
}
|
||||
|
||||
void init_lockingfailed(int level)
|
||||
{
|
||||
_lockingfailed = level;
|
||||
}
|
||||
|
||||
void init_security_level(int level)
|
||||
{
|
||||
_security_level = level;
|
||||
@@ -203,6 +215,16 @@ int pvmove_mode()
|
||||
return _pvmove;
|
||||
}
|
||||
|
||||
int full_scan_done()
|
||||
{
|
||||
return _full_scan_done;
|
||||
}
|
||||
|
||||
int lockingfailed()
|
||||
{
|
||||
return _lockingfailed;
|
||||
}
|
||||
|
||||
int ignorelockingfailure()
|
||||
{
|
||||
return _ignorelockingfailure;
|
||||
|
||||
@@ -65,11 +65,13 @@ void init_test(int level);
|
||||
void init_partial(int level);
|
||||
void init_md_filtering(int level);
|
||||
void init_pvmove(int level);
|
||||
void init_full_scan_done(int level);
|
||||
void init_debug(int level);
|
||||
void init_cmd_name(int status);
|
||||
void init_msg_prefix(const char *prefix);
|
||||
void init_indent(int indent);
|
||||
void init_ignorelockingfailure(int level);
|
||||
void init_lockingfailed(int level);
|
||||
void init_security_level(int level);
|
||||
|
||||
void set_cmd_name(const char *cmd_name);
|
||||
@@ -78,8 +80,10 @@ int test_mode(void);
|
||||
int partial_mode(void);
|
||||
int md_filtering(void);
|
||||
int pvmove_mode(void);
|
||||
int full_scan_done(void);
|
||||
int debug_level(void);
|
||||
int ignorelockingfailure(void);
|
||||
int lockingfailed(void);
|
||||
int security_level(void);
|
||||
|
||||
/* Suppress messages to stdout/stderr */
|
||||
|
||||
@@ -16,5 +16,64 @@
|
||||
#ifndef _LVM_LV_ALLOC_H
|
||||
#include "pool.h"
|
||||
|
||||
struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t num_areas);
|
||||
struct lv_segment *alloc_lv_segment(struct pool *mem,
|
||||
struct segment_type *segtype,
|
||||
struct logical_volume *lv,
|
||||
uint32_t le, uint32_t len,
|
||||
uint32_t status,
|
||||
uint32_t stripe_size,
|
||||
struct logical_volume *log_lv,
|
||||
uint32_t area_count,
|
||||
uint32_t area_len,
|
||||
uint32_t chunk_size,
|
||||
uint32_t region_size,
|
||||
uint32_t extents_copied);
|
||||
|
||||
struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
|
||||
uint32_t status, uint32_t old_le_count);
|
||||
|
||||
int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
|
||||
struct physical_volume *pv, uint32_t pe);
|
||||
void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
|
||||
struct logical_volume *lv, uint32_t le,
|
||||
uint32_t flags);
|
||||
|
||||
struct alloc_handle;
|
||||
struct alloc_handle *allocate_extents(struct volume_group *vg,
|
||||
struct logical_volume *lv,
|
||||
struct segment_type *segtype,
|
||||
uint32_t stripes,
|
||||
uint32_t mirrors, uint32_t log_count,
|
||||
uint32_t extents,
|
||||
struct physical_volume *mirrored_pv,
|
||||
uint32_t mirrored_pe,
|
||||
uint32_t status,
|
||||
struct list *allocatable_pvs,
|
||||
alloc_policy_t alloc);
|
||||
|
||||
int lv_add_segment(struct alloc_handle *ah,
|
||||
uint32_t first_area, uint32_t num_areas,
|
||||
struct logical_volume *lv,
|
||||
struct segment_type *segtype,
|
||||
uint32_t stripe_size,
|
||||
struct physical_volume *mirrored_pv,
|
||||
uint32_t mirrored_pe,
|
||||
uint32_t status,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv);
|
||||
|
||||
int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv);
|
||||
int lv_add_virtual_segment(struct logical_volume *lv, uint32_t status,
|
||||
uint32_t extents, struct segment_type *segtype);
|
||||
int lv_add_mirror_segment(struct alloc_handle *ah,
|
||||
struct logical_volume *lv,
|
||||
struct logical_volume **sub_lvs,
|
||||
uint32_t mirrors,
|
||||
struct segment_type *segtype,
|
||||
uint32_t status,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv);
|
||||
|
||||
void alloc_destroy(struct alloc_handle *ah);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@
|
||||
#include "metadata.h"
|
||||
#include "toolcontext.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "pv_alloc.h"
|
||||
#include "str_list.h"
|
||||
#include "segtype.h"
|
||||
|
||||
@@ -57,11 +58,13 @@ int lv_merge_segments(struct logical_volume *lv)
|
||||
/*
|
||||
* Verify that an LV's segments are consecutive, complete and don't overlap.
|
||||
*/
|
||||
int lv_check_segments(struct logical_volume *lv)
|
||||
int check_lv_segments(struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
uint32_t le = 0;
|
||||
unsigned seg_count = 0;
|
||||
int r = 1;
|
||||
uint32_t area_multiplier, s;
|
||||
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
seg_count++;
|
||||
@@ -69,13 +72,58 @@ int lv_check_segments(struct logical_volume *lv)
|
||||
log_error("LV %s invalid: segment %u should begin at "
|
||||
"LE %" PRIu32 " (found %" PRIu32 ").",
|
||||
lv->name, seg_count, le, seg->le);
|
||||
return 0;
|
||||
r = 0;
|
||||
}
|
||||
|
||||
area_multiplier = segtype_is_striped(seg->segtype) ?
|
||||
seg->area_count : 1;
|
||||
|
||||
if (seg->area_len * area_multiplier != seg->len) {
|
||||
log_error("LV %s: segment %u has inconsistent "
|
||||
"area_len %u",
|
||||
lv->name, seg_count, seg->area_len);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg_type(seg, s) == AREA_PV) {
|
||||
if (!seg_pvseg(seg, s) ||
|
||||
seg_pvseg(seg, s)->lvseg != seg ||
|
||||
seg_pvseg(seg, s)->lv_area != s) {
|
||||
log_error("LV %s: segment %u has "
|
||||
"inconsistent PV area %u",
|
||||
lv->name, seg_count, s);
|
||||
r = 0;
|
||||
}
|
||||
} else {
|
||||
if (!seg_lv(seg, s) ||
|
||||
seg_lv(seg, s)->vg != lv->vg ||
|
||||
seg_lv(seg, s) == lv) {
|
||||
log_error("LV %s: segment %u has "
|
||||
"inconsistent LV area %u",
|
||||
lv->name, seg_count, s);
|
||||
r = 0;
|
||||
}
|
||||
if (seg_le(seg, s) != le) {
|
||||
log_error("LV %s: segment %u has "
|
||||
"inconsistent LV area %u "
|
||||
"size",
|
||||
lv->name, seg_count, s);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
le += seg->len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
if (le != lv->le_count) {
|
||||
log_error("LV %s: inconsistent LE count %u != %u",
|
||||
lv->name, le, lv->le_count);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -85,27 +133,29 @@ int lv_check_segments(struct logical_volume *lv)
|
||||
static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||
uint32_t le)
|
||||
{
|
||||
size_t len;
|
||||
struct lv_segment *split_seg;
|
||||
uint32_t s;
|
||||
uint32_t offset = le - seg->le;
|
||||
uint32_t area_offset;
|
||||
|
||||
if (!(seg->segtype->flags & SEG_CAN_SPLIT)) {
|
||||
if (!seg_can_split(seg)) {
|
||||
log_error("Unable to split the %s segment at LE %" PRIu32
|
||||
" in LV %s", seg->segtype->name, le, lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Clone the existing segment */
|
||||
if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, seg->area_count))) {
|
||||
log_error("Couldn't allocate new LV segment.");
|
||||
if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, seg->segtype,
|
||||
seg->lv, seg->le, seg->len,
|
||||
seg->status, seg->stripe_size,
|
||||
seg->log_lv,
|
||||
seg->area_count, seg->area_len,
|
||||
seg->chunk_size, seg->region_size,
|
||||
seg->extents_copied))) {
|
||||
log_error("Couldn't allocate cloned LV segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = sizeof(*seg) + (seg->area_count * sizeof(seg->area[0]));
|
||||
memcpy(split_seg, seg, len);
|
||||
|
||||
if (!str_list_dup(lv->vg->cmd->mem, &split_seg->tags, &seg->tags)) {
|
||||
log_error("LV segment tags duplication failed");
|
||||
return 0;
|
||||
@@ -113,37 +163,9 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||
|
||||
/* In case of a striped segment, the offset has to be / stripes */
|
||||
area_offset = offset;
|
||||
if (seg->segtype->flags & SEG_AREAS_STRIPED)
|
||||
if (seg_is_striped(seg))
|
||||
area_offset /= seg->area_count;
|
||||
|
||||
/* Adjust the PV mapping */
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
/* Split area at the offset */
|
||||
switch (seg->area[s].type) {
|
||||
case AREA_LV:
|
||||
split_seg->area[s].u.lv.le =
|
||||
seg->area[s].u.lv.le + area_offset;
|
||||
log_debug("Split %s:%u[%u] at %u: %s LE %u", lv->name,
|
||||
seg->le, s, le, seg->area[s].u.lv.lv->name,
|
||||
split_seg->area[s].u.lv.le);
|
||||
break;
|
||||
|
||||
case AREA_PV:
|
||||
split_seg->area[s].u.pv.pe =
|
||||
seg->area[s].u.pv.pe + area_offset;
|
||||
log_debug("Split %s:%u[%u] at %u: %s PE %u", lv->name,
|
||||
seg->le, s, le,
|
||||
dev_name(seg->area[s].u.pv.pv->dev),
|
||||
split_seg->area[s].u.pv.pe);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Unrecognised segment type %u",
|
||||
seg->area[s].type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
split_seg->area_len -= area_offset;
|
||||
seg->area_len = area_offset;
|
||||
|
||||
@@ -152,6 +174,44 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||
|
||||
split_seg->le = seg->le + seg->len;
|
||||
|
||||
/* Adjust the PV mapping */
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
seg_type(split_seg, s) = seg_type(seg, s);
|
||||
|
||||
/* Split area at the offset */
|
||||
switch (seg_type(seg, s)) {
|
||||
case AREA_LV:
|
||||
seg_lv(split_seg, s) = seg_lv(seg, s);
|
||||
seg_le(split_seg, s) =
|
||||
seg_le(seg, s) + seg->area_len;
|
||||
log_debug("Split %s:%u[%u] at %u: %s LE %u", lv->name,
|
||||
seg->le, s, le, seg_lv(seg, s)->name,
|
||||
seg_le(split_seg, s));
|
||||
break;
|
||||
|
||||
case AREA_PV:
|
||||
if (!assign_peg_to_lvseg(seg_pv(seg, s),
|
||||
seg_pe(seg, s) +
|
||||
seg->area_len,
|
||||
seg_pvseg(seg, s)->len -
|
||||
seg->area_len,
|
||||
split_seg, s)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
log_debug("Split %s:%u[%u] at %u: %s PE %u", lv->name,
|
||||
seg->le, s, le,
|
||||
dev_name(seg_dev(seg, s)),
|
||||
seg_pe(split_seg, s));
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Unrecognised segment type %u",
|
||||
seg_type(seg, s));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add split off segment to the list _after_ the original one */
|
||||
list_add_h(&seg->list, &split_seg->list);
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include "lvm-string.h"
|
||||
#include "lvmcache.h"
|
||||
#include "memlock.h"
|
||||
#include "str_list.h"
|
||||
#include "pv_alloc.h"
|
||||
|
||||
static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
|
||||
const char *pv_name)
|
||||
@@ -99,9 +101,14 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
pvl->pv = pv;
|
||||
if (!alloc_pv_segment_whole_pv(mem, pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pvl->pv = pv;
|
||||
list_add(&vg->pvs, &pvl->list);
|
||||
|
||||
vg->pv_count++;
|
||||
vg->extent_count += pv->pe_count;
|
||||
vg->free_count += pv->pe_count;
|
||||
@@ -109,23 +116,70 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _copy_pv(struct physical_volume *pv_to,
|
||||
struct physical_volume *pv_from)
|
||||
{
|
||||
memcpy(pv_to, pv_from, sizeof(*pv_to));
|
||||
|
||||
if (!str_list_dup(pv_to->fmt->cmd->mem, &pv_to->tags, &pv_from->tags)) {
|
||||
log_error("PV tags duplication failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!peg_dup(pv_to->fmt->cmd->mem, &pv_to->segments,
|
||||
&pv_from->segments)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
|
||||
const char *id, struct physical_volume *pv)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct pv_list *pvl;
|
||||
int consistent = 0;
|
||||
|
||||
if (!(vg = vg_read(fmt->cmd, vg_name, &consistent))) {
|
||||
log_error("get_pv_from_vg_by_id: vg_read failed to read VG %s",
|
||||
vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!consistent)
|
||||
log_error("Warning: Volume group %s is not consistent",
|
||||
vg_name);
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (id_equal(&pvl->pv->id, (const struct id *) id)) {
|
||||
if (!_copy_pv(pv, pvl->pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *new_name)
|
||||
{
|
||||
struct pool *mem = cmd->mem;
|
||||
struct physical_volume *pv;
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
|
||||
if (!(vg->name = pool_strdup(mem, new_name))) {
|
||||
log_error("vg->name allocation failed for '%s'", new_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
if (!(pv->vg_name = pool_strdup(mem, new_name))) {
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (!(pvl->pv->vg_name = pool_strdup(mem, new_name))) {
|
||||
log_error("pv->vg_name allocation failed for '%s'",
|
||||
dev_name(pv->dev));
|
||||
dev_name(pvl->pv->dev));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -221,7 +275,6 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
list_init(&vg->lvs);
|
||||
|
||||
vg->snapshot_count = 0;
|
||||
list_init(&vg->snapshots);
|
||||
|
||||
list_init(&vg->tags);
|
||||
|
||||
@@ -249,6 +302,182 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _recalc_extents(uint32_t *extents, const char *desc1,
|
||||
const char *desc2, uint32_t old_size,
|
||||
uint32_t new_size)
|
||||
{
|
||||
uint64_t size = (uint64_t) old_size * (*extents);
|
||||
|
||||
if (size % new_size) {
|
||||
log_error("New size %" PRIu64 " for %s%s not an exact number "
|
||||
"of new extents.", size, desc1, desc2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size /= new_size;
|
||||
|
||||
if (size > UINT32_MAX) {
|
||||
log_error("New extent count %" PRIu64 " for %s%s exceeds "
|
||||
"32 bits.", size, desc1, desc2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*extents = (uint32_t) size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
||||
uint32_t new_size)
|
||||
{
|
||||
uint32_t old_size = vg->extent_size;
|
||||
struct pv_list *pvl;
|
||||
struct lv_list *lvl;
|
||||
struct physical_volume *pv;
|
||||
struct logical_volume *lv;
|
||||
struct lv_segment *seg;
|
||||
struct pv_segment *pvseg;
|
||||
uint32_t s;
|
||||
|
||||
vg->extent_size = new_size;
|
||||
|
||||
if (vg->fid->fmt->ops->vg_setup &&
|
||||
!vg->fid->fmt->ops->vg_setup(vg->fid, vg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_recalc_extents(&vg->extent_count, vg->name, "", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_recalc_extents(&vg->free_count, vg->name, " free space",
|
||||
old_size, new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* foreach PV */
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
pv = pvl->pv;
|
||||
|
||||
pv->pe_size = new_size;
|
||||
if (!_recalc_extents(&pv->pe_count, dev_name(pv->dev), "",
|
||||
old_size, new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_recalc_extents(&pv->pe_alloc_count, dev_name(pv->dev),
|
||||
" allocated space", old_size, new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* foreach free PV Segment */
|
||||
list_iterate_items(pvseg, &pv->segments) {
|
||||
if (pvseg->lvseg)
|
||||
continue;
|
||||
|
||||
if (!_recalc_extents(&pvseg->pe, dev_name(pv->dev),
|
||||
" PV segment start", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!_recalc_extents(&pvseg->len, dev_name(pv->dev),
|
||||
" PV segment length", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* foreach LV */
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
lv = lvl->lv;
|
||||
|
||||
if (!_recalc_extents(&lv->le_count, lv->name, "", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (!_recalc_extents(&seg->le, lv->name,
|
||||
" segment start", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_recalc_extents(&seg->len, lv->name,
|
||||
" segment length", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_recalc_extents(&seg->area_len, lv->name,
|
||||
" area length", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_recalc_extents(&seg->extents_copied, lv->name,
|
||||
" extents moved", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* foreach area */
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
switch (seg_type(seg, s)) {
|
||||
case AREA_PV:
|
||||
if (!_recalc_extents
|
||||
(&seg_pe(seg, s),
|
||||
lv->name,
|
||||
" pvseg start", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!_recalc_extents
|
||||
(&seg_pvseg(seg, s)->len,
|
||||
lv->name,
|
||||
" pvseg length", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case AREA_LV:
|
||||
if (!_recalc_extents
|
||||
(&seg_le(seg, s), lv->name,
|
||||
" area start", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_error("Unrecognised segment type "
|
||||
"%u", seg_type(seg, s));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Sizes in sectors */
|
||||
struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
@@ -267,10 +496,13 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!id)
|
||||
id_create(&pv->id);
|
||||
else
|
||||
if (id)
|
||||
memcpy(&pv->id, id, sizeof(*id));
|
||||
else if (!id_create(&pv->id)) {
|
||||
log_error("Failed to create random uuid for %s.",
|
||||
dev_name(dev));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pv->dev = dev;
|
||||
|
||||
@@ -308,6 +540,7 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
pv->fmt = fmt;
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
|
||||
if (!fmt->ops->pv_setup(fmt, pe_start, existing_extent_count,
|
||||
existing_extent_size,
|
||||
@@ -326,26 +559,22 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
|
||||
struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
list_iterate_items(pvl, &vg->pvs)
|
||||
if (pvl->pv->dev == dev_cache_get(pv_name, vg->cmd->filter))
|
||||
return pvl;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
if (pv == list_item(pvh, struct pv_list)->pv)
|
||||
list_iterate_items(pvl, &vg->pvs)
|
||||
if (pv == pvl->pv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -353,21 +582,17 @@ int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv)
|
||||
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
|
||||
struct id *id)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
list_iterate_items(pvl, &vg->pvs)
|
||||
if (id_equal(&pvl->pv->id, id))
|
||||
return pvl->pv;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct lv_list *lvl;
|
||||
const char *ptr;
|
||||
|
||||
@@ -377,11 +602,9 @@ struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name)
|
||||
else
|
||||
ptr = lv_name;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lvl = list_item(lvh, struct lv_list);
|
||||
list_iterate_items(lvl, &vg->lvs)
|
||||
if (!strcmp(lvl->lv->name, ptr))
|
||||
return lvl;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -389,14 +612,11 @@ struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name)
|
||||
struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg,
|
||||
const union lvid *lvid)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct lv_list *lvl;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lvl = list_item(lvh, struct lv_list);
|
||||
list_iterate_items(lvl, &vg->lvs)
|
||||
if (!strncmp(lvl->lv->lvid.s, lvid->s, sizeof(*lvid)))
|
||||
return lvl;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -409,15 +629,12 @@ struct logical_volume *find_lv(struct volume_group *vg, const char *lv_name)
|
||||
|
||||
struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct physical_volume *pv;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
list_iterate_items(pvl, &vg->pvs)
|
||||
if (dev == pvl->pv->dev)
|
||||
return pvl->pv;
|
||||
|
||||
if (dev == pv->dev)
|
||||
return pv;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -442,27 +659,34 @@ struct physical_volume *find_pv_by_name(struct cmd_context *cmd,
|
||||
/* Find segment at a given logical extent in an LV */
|
||||
struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le)
|
||||
{
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments)
|
||||
if (le >= seg->le && le < seg->le + seg->len)
|
||||
return seg;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find segment at a given physical extent in a PV */
|
||||
struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe)
|
||||
{
|
||||
struct pv_segment *peg;
|
||||
|
||||
list_iterate_items(peg, &pv->segments)
|
||||
if (pe >= peg->pe && pe < peg->pe + peg->len)
|
||||
return peg;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int vg_remove(struct volume_group *vg)
|
||||
{
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
|
||||
/* FIXME Improve recovery situation? */
|
||||
/* Remove each copy of the metadata */
|
||||
list_iterate(mdah, &vg->fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &vg->fid->metadata_areas) {
|
||||
if (mda->ops->vg_remove &&
|
||||
!mda->ops->vg_remove(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
@@ -479,8 +703,23 @@ int vg_remove(struct volume_group *vg)
|
||||
*/
|
||||
int vg_write(struct volume_group *vg)
|
||||
{
|
||||
struct list *mdah, *mdah2;
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
struct lv_list *lvl;
|
||||
|
||||
if (!check_pv_segments(vg)) {
|
||||
log_error("Internal error: PV segments corrupted in %s.",
|
||||
vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if (!check_lv_segments(lvl->lv)) {
|
||||
log_error("Internal error: LV segments corrupted in %s.",
|
||||
lvl->lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (vg->status & PARTIAL_VG) {
|
||||
log_error("Cannot change metadata for partial volume group %s",
|
||||
@@ -496,14 +735,14 @@ int vg_write(struct volume_group *vg)
|
||||
vg->seqno++;
|
||||
|
||||
/* Write to each copy of the metadata area */
|
||||
list_iterate(mdah, &vg->fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &vg->fid->metadata_areas) {
|
||||
if (!mda->ops->vg_write) {
|
||||
log_error("Format does not support writing volume"
|
||||
"group metadata areas");
|
||||
/* Revert */
|
||||
list_uniterate(mdah2, &vg->fid->metadata_areas, mdah) {
|
||||
mda = list_item(mdah2, struct metadata_area);
|
||||
list_uniterate(mdah, &vg->fid->metadata_areas, &mda->list) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
|
||||
if (mda->ops->vg_revert &&
|
||||
!mda->ops->vg_revert(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
@@ -514,8 +753,25 @@ int vg_write(struct volume_group *vg)
|
||||
if (!mda->ops->vg_write(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
/* Revert */
|
||||
list_uniterate(mdah2, &vg->fid->metadata_areas, mdah) {
|
||||
mda = list_item(mdah2, struct metadata_area);
|
||||
list_uniterate(mdah, &vg->fid->metadata_areas, &mda->list) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
|
||||
if (mda->ops->vg_revert &&
|
||||
!mda->ops->vg_revert(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now pre-commit each copy of the new metadata */
|
||||
list_iterate_items(mda, &vg->fid->metadata_areas) {
|
||||
if (mda->ops->vg_precommit &&
|
||||
!mda->ops->vg_precommit(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
/* Revert */
|
||||
list_iterate_items(mda, &vg->fid->metadata_areas) {
|
||||
if (mda->ops->vg_revert &&
|
||||
!mda->ops->vg_revert(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
@@ -531,14 +787,12 @@ int vg_write(struct volume_group *vg)
|
||||
/* Commit pending changes */
|
||||
int vg_commit(struct volume_group *vg)
|
||||
{
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
int cache_updated = 0;
|
||||
int failed = 0;
|
||||
|
||||
/* Commit to each copy of the metadata area */
|
||||
list_iterate(mdah, &vg->fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &vg->fid->metadata_areas) {
|
||||
failed = 0;
|
||||
if (mda->ops->vg_commit &&
|
||||
!mda->ops->vg_commit(vg->fid, vg, mda)) {
|
||||
@@ -550,7 +804,6 @@ int vg_commit(struct volume_group *vg)
|
||||
lvmcache_update_vg(vg);
|
||||
cache_updated = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* If at least one mda commit succeeded, it was committed */
|
||||
@@ -560,11 +813,9 @@ int vg_commit(struct volume_group *vg)
|
||||
/* Don't commit any pending changes */
|
||||
int vg_revert(struct volume_group *vg)
|
||||
{
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
|
||||
list_iterate(mdah, &vg->fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &vg->fid->metadata_areas) {
|
||||
if (mda->ops->vg_revert &&
|
||||
!mda->ops->vg_revert(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
@@ -578,8 +829,7 @@ int vg_revert(struct volume_group *vg)
|
||||
static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct list *ih;
|
||||
struct device *dev;
|
||||
struct lvmcache_info *info;
|
||||
struct pv_list *pvl;
|
||||
struct volume_group *vg;
|
||||
struct physical_volume *pv;
|
||||
@@ -595,7 +845,6 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
}
|
||||
list_init(&vg->pvs);
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
list_init(&vg->tags);
|
||||
vg->cmd = cmd;
|
||||
if (!(vg->name = pool_strdup(cmd->mem, ORPHAN))) {
|
||||
@@ -603,9 +852,8 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate(ih, &vginfo->infos) {
|
||||
dev = list_item(ih, struct lvmcache_info)->dev;
|
||||
if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL, 1))) {
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
if (!(pv = pv_read(cmd, dev_name(info->dev), NULL, NULL, 1))) {
|
||||
continue;
|
||||
}
|
||||
if (!(pvl = pool_zalloc(cmd->mem, sizeof(*pvl)))) {
|
||||
@@ -627,17 +875,22 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
* and take appropriate action if it isn't (e.g. abort; get write lock
|
||||
* and call vg_read again).
|
||||
*/
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
int *consistent)
|
||||
static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
const char *vgname,
|
||||
int *consistent, int precommitted)
|
||||
{
|
||||
struct format_instance *fid;
|
||||
const struct format_type *fmt;
|
||||
struct volume_group *vg, *correct_vg = NULL;
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
int inconsistent = 0;
|
||||
|
||||
if (!*vgname) {
|
||||
if (precommitted) {
|
||||
log_error("Internal error: vg_read requires vgname "
|
||||
"with pre-commit.");
|
||||
return NULL;
|
||||
}
|
||||
*consistent = 1;
|
||||
return _vg_read_orphans(cmd);
|
||||
}
|
||||
@@ -651,7 +904,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
lvmcache_label_scan(cmd, 1);
|
||||
lvmcache_label_scan(cmd, 2);
|
||||
if (!(fmt = fmt_from_vgname(vgname))) {
|
||||
stack;
|
||||
return NULL;
|
||||
@@ -659,6 +912,12 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
}
|
||||
}
|
||||
|
||||
if (precommitted && !(fmt->features & FMT_PRECOMMIT)) {
|
||||
log_error("Internal error: %s doesn't support "
|
||||
"pre-commit", fmt->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create format instance with appropriate metadata area */
|
||||
if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
|
||||
log_error("Failed to create format instance");
|
||||
@@ -666,9 +925,11 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
}
|
||||
|
||||
/* Ensure contents of all metadata areas match - else do recovery */
|
||||
list_iterate(mdah, &fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
if (!(vg = mda->ops->vg_read(fid, vgname, mda))) {
|
||||
list_iterate_items(mda, &fid->metadata_areas) {
|
||||
if ((precommitted &&
|
||||
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda))) ||
|
||||
(!precommitted &&
|
||||
!(vg = mda->ops->vg_read(fid, vgname, mda)))) {
|
||||
inconsistent = 1;
|
||||
continue;
|
||||
}
|
||||
@@ -684,15 +945,66 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
}
|
||||
}
|
||||
|
||||
/* Failed to find VG */
|
||||
/* Failed to find VG where we expected it - full scan and retry */
|
||||
if (!correct_vg) {
|
||||
stack;
|
||||
return NULL;
|
||||
inconsistent = 0;
|
||||
|
||||
lvmcache_label_scan(cmd, 2);
|
||||
if (!(fmt = fmt_from_vgname(vgname))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (precommitted && !(fmt->features & FMT_PRECOMMIT)) {
|
||||
log_error("Internal error: %s doesn't support "
|
||||
"pre-commit", fmt->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create format instance with appropriate metadata area */
|
||||
if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
|
||||
log_error("Failed to create format instance");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Ensure contents of all metadata areas match - else recover */
|
||||
list_iterate_items(mda, &fid->metadata_areas) {
|
||||
if ((precommitted &&
|
||||
!(vg = mda->ops->vg_read_precommit(fid, vgname,
|
||||
mda))) ||
|
||||
(!precommitted &&
|
||||
!(vg = mda->ops->vg_read(fid, vgname, mda)))) {
|
||||
inconsistent = 1;
|
||||
continue;
|
||||
}
|
||||
if (!correct_vg) {
|
||||
correct_vg = vg;
|
||||
continue;
|
||||
}
|
||||
/* FIXME Also ensure contents same - checksums same? */
|
||||
if (correct_vg->seqno != vg->seqno) {
|
||||
inconsistent = 1;
|
||||
if (vg->seqno > correct_vg->seqno)
|
||||
correct_vg = vg;
|
||||
}
|
||||
}
|
||||
|
||||
/* Give up looking */
|
||||
if (!correct_vg) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
lvmcache_update_vg(correct_vg);
|
||||
|
||||
if (inconsistent) {
|
||||
if (precommitted) {
|
||||
log_error("Inconsistent pre-commit metadata copies "
|
||||
"for volume group %s", vgname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!*consistent)
|
||||
return correct_vg;
|
||||
|
||||
@@ -730,6 +1042,19 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
return correct_vg;
|
||||
}
|
||||
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
int *consistent)
|
||||
{
|
||||
return _vg_read(cmd, vgname, consistent, 0);
|
||||
}
|
||||
|
||||
struct volume_group *vg_read_precommitted(struct cmd_context *cmd,
|
||||
const char *vgname,
|
||||
int *consistent)
|
||||
{
|
||||
return _vg_read(cmd, vgname, consistent, 1);
|
||||
}
|
||||
|
||||
/* This is only called by lv_from_lvid, which is only called from
|
||||
* activate.c so we know the appropriate VG lock is already held and
|
||||
* the vg_read is therefore safe.
|
||||
@@ -737,9 +1062,10 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid)
|
||||
{
|
||||
const char *vgname;
|
||||
struct list *vgnames, *slh;
|
||||
struct list *vgnames;
|
||||
struct volume_group *vg;
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct str_list *strl;
|
||||
int consistent = 0;
|
||||
|
||||
/* Is corresponding vgname already cached? */
|
||||
@@ -765,13 +1091,13 @@ struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid)
|
||||
* allowed to do a full scan here any more. */
|
||||
|
||||
// The slow way - full scan required to cope with vgrename
|
||||
if (!(vgnames = get_vgs(cmd, 1))) {
|
||||
if (!(vgnames = get_vgs(cmd, 2))) {
|
||||
log_error("vg_read_by_vgid: get_vgs failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate(slh, vgnames) {
|
||||
vgname = list_item(slh, struct str_list)->str;
|
||||
list_iterate_items(strl, vgnames) {
|
||||
vgname = strl->str;
|
||||
if (!vgname || !*vgname)
|
||||
continue; // FIXME Unnecessary?
|
||||
consistent = 0;
|
||||
@@ -829,14 +1155,14 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||
|
||||
if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
|
||||
stack;
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(label_read(dev, &label))) {
|
||||
if (warnings)
|
||||
log_error("No physical volume label read from %s",
|
||||
pv_name);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
@@ -845,22 +1171,28 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||
|
||||
if (!(pv = pool_zalloc(cmd->mem, sizeof(*pv)))) {
|
||||
log_error("pv allocation for '%s' failed", pv_name);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
|
||||
/* FIXME Move more common code up here */
|
||||
if (!(info->fmt->ops->pv_read(info->fmt, pv_name, pv, mdas))) {
|
||||
log_error("Failed to read existing physical volume '%s'",
|
||||
pv_name);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!pv->size)
|
||||
return NULL;
|
||||
else
|
||||
return pv;
|
||||
|
||||
if (!alloc_pv_segment_whole_pv(cmd->mem, pv)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pv;
|
||||
}
|
||||
|
||||
/* May return empty list */
|
||||
@@ -871,10 +1203,11 @@ struct list *get_vgs(struct cmd_context *cmd, int full_scan)
|
||||
|
||||
struct list *get_pvs(struct cmd_context *cmd)
|
||||
{
|
||||
struct str_list *strl;
|
||||
struct list *results;
|
||||
const char *vgname;
|
||||
struct list *pvh, *tmp;
|
||||
struct list *vgnames, *slh;
|
||||
struct list *vgnames;
|
||||
struct volume_group *vg;
|
||||
int consistent = 0;
|
||||
int old_partial;
|
||||
@@ -901,8 +1234,8 @@ struct list *get_pvs(struct cmd_context *cmd)
|
||||
old_pvmove = pvmove_mode();
|
||||
init_partial(1);
|
||||
init_pvmove(1);
|
||||
list_iterate(slh, vgnames) {
|
||||
vgname = list_item(slh, struct str_list)->str;
|
||||
list_iterate_items(strl, vgnames) {
|
||||
vgname = strl->str;
|
||||
if (!vgname)
|
||||
continue; /* FIXME Unnecessary? */
|
||||
consistent = 0;
|
||||
|
||||
@@ -50,11 +50,13 @@
|
||||
#define VISIBLE_LV 0x00000040 /* LV */
|
||||
#define FIXED_MINOR 0x00000080 /* LV */
|
||||
/* FIXME Remove when metadata restructuring is completed */
|
||||
#define SNAPSHOT 0x00001000 /* LV - tmp internal use only */
|
||||
#define SNAPSHOT 0x00001000 /* LV - internal use only */
|
||||
#define PVMOVE 0x00002000 /* VG LV SEG */
|
||||
#define LOCKED 0x00004000 /* LV */
|
||||
#define MIRRORED 0x00008000 /* LV - internal use only */
|
||||
#define VIRTUAL 0x00010000 /* LV - internal use only */
|
||||
#define MIRROR_LOG 0x00020000 /* LV */
|
||||
#define MIRROR_IMAGE 0x00040000 /* LV */
|
||||
|
||||
#define LVM_READ 0x00000100 /* LV VG */
|
||||
#define LVM_WRITE 0x00000200 /* LV VG */
|
||||
@@ -68,6 +70,7 @@
|
||||
#define FMT_UNLIMITED_VOLS 0x00000008 /* Unlimited PVs/LVs? */
|
||||
#define FMT_RESTRICTED_LVIDS 0x00000010 /* LVID <= 255 */
|
||||
#define FMT_ORPHAN_ALLOCATABLE 0x00000020 /* Orphan PV allocatable? */
|
||||
#define FMT_PRECOMMIT 0x00000040 /* Supports pre-commit? */
|
||||
|
||||
typedef enum {
|
||||
ALLOC_INVALID,
|
||||
@@ -98,6 +101,18 @@ struct format_type {
|
||||
void *private;
|
||||
};
|
||||
|
||||
struct pv_segment {
|
||||
struct list list; /* Member of pv->segments: ordered list
|
||||
* covering entire data area on this PV */
|
||||
|
||||
struct physical_volume *pv;
|
||||
uint32_t pe;
|
||||
uint32_t len;
|
||||
|
||||
struct lv_segment *lvseg; /* NULL if free space */
|
||||
uint32_t lv_area; /* Index to area in LV segment */
|
||||
};
|
||||
|
||||
struct physical_volume {
|
||||
struct id id;
|
||||
struct device *dev;
|
||||
@@ -113,6 +128,7 @@ struct physical_volume {
|
||||
uint32_t pe_count;
|
||||
uint32_t pe_alloc_count;
|
||||
|
||||
struct list segments; /* Ordered pv_segments covering complete PV */
|
||||
struct list tags;
|
||||
};
|
||||
|
||||
@@ -124,6 +140,9 @@ struct metadata_area_ops {
|
||||
struct volume_group *(*vg_read) (struct format_instance * fi,
|
||||
const char *vg_name,
|
||||
struct metadata_area * mda);
|
||||
struct volume_group *(*vg_read_precommit) (struct format_instance * fi,
|
||||
const char *vg_name,
|
||||
struct metadata_area * mda);
|
||||
/*
|
||||
* Write out complete VG metadata. You must ensure internal
|
||||
* consistency before calling. eg. PEs can't refer to PVs not
|
||||
@@ -140,6 +159,9 @@ struct metadata_area_ops {
|
||||
*/
|
||||
int (*vg_write) (struct format_instance * fid, struct volume_group * vg,
|
||||
struct metadata_area * mda);
|
||||
int (*vg_precommit) (struct format_instance * fid,
|
||||
struct volume_group * vg,
|
||||
struct metadata_area * mda);
|
||||
int (*vg_commit) (struct format_instance * fid,
|
||||
struct volume_group * vg, struct metadata_area * mda);
|
||||
int (*vg_revert) (struct format_instance * fid,
|
||||
@@ -184,11 +206,8 @@ struct volume_group {
|
||||
|
||||
/* logical volumes */
|
||||
uint32_t lv_count;
|
||||
struct list lvs;
|
||||
|
||||
/* snapshots */
|
||||
uint32_t snapshot_count;
|
||||
struct list snapshots;
|
||||
struct list lvs;
|
||||
|
||||
struct list tags;
|
||||
};
|
||||
@@ -210,8 +229,11 @@ struct lv_segment {
|
||||
uint32_t area_len;
|
||||
struct logical_volume *origin;
|
||||
struct logical_volume *cow;
|
||||
uint32_t chunk_size;
|
||||
struct list origin_list;
|
||||
uint32_t chunk_size; /* For snapshots - in sectors */
|
||||
uint32_t region_size; /* For mirrors - in sectors */
|
||||
uint32_t extents_copied;
|
||||
struct logical_volume *log_lv;
|
||||
|
||||
struct list tags;
|
||||
|
||||
@@ -220,8 +242,7 @@ struct lv_segment {
|
||||
area_type_t type;
|
||||
union {
|
||||
struct {
|
||||
struct physical_volume *pv;
|
||||
uint32_t pe;
|
||||
struct pv_segment *pvseg;
|
||||
} pv;
|
||||
struct {
|
||||
struct logical_volume *lv;
|
||||
@@ -231,6 +252,14 @@ struct lv_segment {
|
||||
} area[0];
|
||||
};
|
||||
|
||||
#define seg_type(seg, s) (seg)->area[(s)].type
|
||||
#define seg_pvseg(seg, s) (seg)->area[(s)].u.pv.pvseg
|
||||
#define seg_pv(seg, s) (seg)->area[(s)].u.pv.pvseg->pv
|
||||
#define seg_dev(seg, s) (seg)->area[(s)].u.pv.pvseg->pv->dev
|
||||
#define seg_pe(seg, s) (seg)->area[(s)].u.pv.pvseg->pe
|
||||
#define seg_lv(seg, s) (seg)->area[(s)].u.lv.lv
|
||||
#define seg_le(seg, s) (seg)->area[(s)].u.lv.le
|
||||
|
||||
struct logical_volume {
|
||||
union lvid lvid;
|
||||
char *name;
|
||||
@@ -246,20 +275,14 @@ struct logical_volume {
|
||||
uint64_t size;
|
||||
uint32_t le_count;
|
||||
|
||||
uint32_t origin_count;
|
||||
struct list snapshot_segs;
|
||||
struct lv_segment *snapshot;
|
||||
|
||||
struct list segments;
|
||||
struct list tags;
|
||||
};
|
||||
|
||||
struct snapshot {
|
||||
struct id id;
|
||||
|
||||
int persistent; /* boolean */
|
||||
uint32_t chunk_size; /* in 512 byte sectors */
|
||||
|
||||
struct logical_volume *origin;
|
||||
struct logical_volume *cow;
|
||||
};
|
||||
|
||||
struct name_list {
|
||||
struct list list;
|
||||
char *name;
|
||||
@@ -283,17 +306,16 @@ struct lv_list {
|
||||
struct logical_volume *lv;
|
||||
};
|
||||
|
||||
struct snapshot_list {
|
||||
struct list list;
|
||||
|
||||
struct snapshot *snapshot;
|
||||
};
|
||||
|
||||
struct mda_list {
|
||||
struct list list;
|
||||
struct device_area mda;
|
||||
};
|
||||
|
||||
struct peg_list {
|
||||
struct list list;
|
||||
struct pv_segment *peg;
|
||||
};
|
||||
|
||||
/*
|
||||
* Ownership of objects passes to caller.
|
||||
*/
|
||||
@@ -373,6 +395,9 @@ int vg_commit(struct volume_group *vg);
|
||||
int vg_revert(struct volume_group *vg);
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
||||
int *consistent);
|
||||
struct volume_group *vg_read_precommitted(struct cmd_context *cmd,
|
||||
const char *vg_name,
|
||||
int *consistent);
|
||||
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid);
|
||||
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||
struct list *mdas, uint64_t *label_sector,
|
||||
@@ -406,20 +431,23 @@ int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *new_name);
|
||||
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);
|
||||
|
||||
/* Manipulate LVs */
|
||||
struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
const char *name,
|
||||
const char *name_format,
|
||||
union lvid *lvid,
|
||||
uint32_t status,
|
||||
alloc_policy_t alloc,
|
||||
int import,
|
||||
struct volume_group *vg);
|
||||
|
||||
int lv_reduce(struct format_instance *fi,
|
||||
struct logical_volume *lv, uint32_t extents);
|
||||
/* Entry point for all LV extent reductions */
|
||||
int lv_reduce(struct logical_volume *lv, uint32_t extents);
|
||||
|
||||
int lv_extend(struct format_instance *fid,
|
||||
struct logical_volume *lv,
|
||||
/* Entry point for all LV extent allocations */
|
||||
int lv_extend(struct logical_volume *lv,
|
||||
struct segment_type *segtype,
|
||||
uint32_t stripes, uint32_t stripe_size,
|
||||
uint32_t mirrors, uint32_t extents,
|
||||
@@ -427,8 +455,8 @@ int lv_extend(struct format_instance *fid,
|
||||
uint32_t status, struct list *allocatable_pvs,
|
||||
alloc_policy_t alloc);
|
||||
|
||||
/* lv must be part of vg->lvs */
|
||||
int lv_remove(struct volume_group *vg, struct logical_volume *lv);
|
||||
/* lv must be part of lv->vg->lvs */
|
||||
int lv_remove(struct logical_volume *lv);
|
||||
|
||||
/* Manipulate PV structures */
|
||||
int pv_add(struct volume_group *vg, struct physical_volume *pv);
|
||||
@@ -439,6 +467,8 @@ struct physical_volume *pv_find(struct volume_group *vg, const char *pv_name);
|
||||
struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name);
|
||||
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
|
||||
struct id *id);
|
||||
int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
|
||||
const char *id, struct physical_volume *pv);
|
||||
|
||||
/* Find an LV within a given VG */
|
||||
struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name);
|
||||
@@ -462,6 +492,9 @@ struct physical_volume *find_pv_by_name(struct cmd_context *cmd,
|
||||
/* Find LV segment containing given LE */
|
||||
struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le);
|
||||
|
||||
/* Find PV segment containing given LE */
|
||||
struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe);
|
||||
|
||||
/*
|
||||
* Remove a dev_dir if present.
|
||||
*/
|
||||
@@ -470,7 +503,7 @@ const char *strip_dir(const char *vg_name, const char *dir);
|
||||
/*
|
||||
* Checks that an lv has no gaps or overlapping segments.
|
||||
*/
|
||||
int lv_check_segments(struct logical_volume *lv);
|
||||
int check_lv_segments(struct logical_volume *lv);
|
||||
|
||||
/*
|
||||
* Sometimes (eg, after an lvextend), it is possible to merge two
|
||||
@@ -492,24 +525,34 @@ int lv_is_cow(const struct logical_volume *lv);
|
||||
|
||||
int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv);
|
||||
|
||||
struct snapshot *find_cow(const struct logical_volume *lv);
|
||||
struct snapshot *find_origin(const struct logical_volume *lv);
|
||||
struct list *find_snapshots(const struct logical_volume *lv);
|
||||
struct lv_segment *find_cow(const struct logical_volume *lv);
|
||||
|
||||
int vg_add_snapshot(struct logical_volume *origin,
|
||||
struct logical_volume *cow,
|
||||
int persistent, struct id *id, uint32_t chunk_size);
|
||||
int vg_add_snapshot(struct format_instance *fid, const char *name,
|
||||
struct logical_volume *origin, struct logical_volume *cow,
|
||||
union lvid *lvid, uint32_t extent_count,
|
||||
uint32_t chunk_size);
|
||||
|
||||
int vg_remove_snapshot(struct logical_volume *cow);
|
||||
|
||||
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow);
|
||||
|
||||
/*
|
||||
* Mirroring functions
|
||||
*/
|
||||
struct alloc_handle;
|
||||
int create_mirror_layers(struct alloc_handle *ah,
|
||||
uint32_t first_area,
|
||||
uint32_t num_mirrors,
|
||||
struct logical_volume *lv,
|
||||
struct segment_type *segtype,
|
||||
uint32_t status,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv);
|
||||
int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
struct logical_volume *lv_mirr,
|
||||
struct list *source_pvl,
|
||||
struct logical_volume *lv,
|
||||
struct list *allocatable_pvs,
|
||||
alloc_policy_t alloc,
|
||||
struct list *lvs_changed);
|
||||
int remove_pvmove_mirrors(struct volume_group *vg,
|
||||
struct logical_volume *lv_mirr);
|
||||
@@ -526,6 +569,8 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct logical_volume *lv);
|
||||
|
||||
uint32_t find_free_lvnum(struct logical_volume *lv);
|
||||
char *generate_lv_name(struct volume_group *vg, const char *format,
|
||||
char *buffer, size_t len);
|
||||
|
||||
static inline int validate_name(const char *n)
|
||||
{
|
||||
@@ -539,6 +584,9 @@ static inline int validate_name(const char *n)
|
||||
if (*n == '-')
|
||||
return 0;
|
||||
|
||||
if (!strcmp(n, ".") || !strcmp(n, ".."))
|
||||
return 0;
|
||||
|
||||
while ((len++, c = *n++))
|
||||
if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+')
|
||||
return 0;
|
||||
|
||||
@@ -19,6 +19,142 @@
|
||||
#include "segtype.h"
|
||||
#include "display.h"
|
||||
#include "activate.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
/*
|
||||
* Reduce mirrored_seg to num_mirrors images.
|
||||
*/
|
||||
int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors)
|
||||
{
|
||||
uint32_t m;
|
||||
|
||||
for (m = num_mirrors; m < mirrored_seg->area_count; m++) {
|
||||
if (!lv_remove(seg_lv(mirrored_seg, m))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mirrored_seg->area_count = num_mirrors;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int remove_all_mirror_images(struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *first_seg, *seg;
|
||||
struct logical_volume *lv1;
|
||||
|
||||
list_iterate_items(first_seg, &lv->segments)
|
||||
break;
|
||||
|
||||
if (!remove_mirror_images(first_seg, 1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_remove(first_seg->log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv1 = seg_lv(first_seg, 0);
|
||||
|
||||
lv->segments = lv1->segments;
|
||||
lv->segments.n->p = &lv->segments;
|
||||
lv->segments.p->n = &lv->segments;
|
||||
|
||||
list_init(&lv1->segments);
|
||||
lv1->le_count = 0;
|
||||
lv1->size = 0;
|
||||
if (!lv_remove(lv1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->status &= ~MIRRORED;
|
||||
|
||||
list_iterate_items(seg, &lv->segments)
|
||||
seg->lv = lv;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add mirror images to an existing mirror
|
||||
*/
|
||||
/* FIXME
|
||||
int add_mirror_images(struct alloc_handle *ah,
|
||||
uint32_t first_area,
|
||||
uint32_t num_areas,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
int create_mirror_layers(struct alloc_handle *ah,
|
||||
uint32_t first_area,
|
||||
uint32_t num_mirrors,
|
||||
struct logical_volume *lv,
|
||||
struct segment_type *segtype,
|
||||
uint32_t status,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv)
|
||||
{
|
||||
uint32_t m;
|
||||
struct logical_volume **img_lvs;
|
||||
char *img_name;
|
||||
size_t len;
|
||||
|
||||
if (!(img_lvs = alloca(sizeof(*img_lvs) * num_mirrors))) {
|
||||
log_error("img_lvs allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = strlen(lv->name) + 32;
|
||||
if (!(img_name = alloca(len))) {
|
||||
log_error("img_name allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(img_name, len, "%s_mimage_%%d", lv->name) < 0) {
|
||||
log_error("img_name allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (m = 0; m < num_mirrors; m++) {
|
||||
if (!(img_lvs[m] = lv_create_empty(lv->vg->fid, img_name,
|
||||
NULL, LVM_READ | LVM_WRITE,
|
||||
ALLOC_INHERIT, 0, lv->vg))) {\
|
||||
log_error("Aborting. Failed to create submirror LV. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_add_segment(ah, m, 1, img_lvs[m],
|
||||
get_segtype_from_string(lv->vg->cmd,
|
||||
"striped"),
|
||||
0, NULL, 0, 0, 0, NULL)) {
|
||||
log_error("Aborting. Failed to add submirror segment "
|
||||
"to %s. Remove new LV and retry.",
|
||||
img_lvs[m]->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lv_add_mirror_segment(ah, lv, img_lvs, num_mirrors, segtype,
|
||||
0, region_size, log_lv)) {
|
||||
log_error("Aborting. Failed to add mirror segment. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace any LV segments on given PV with temporary mirror.
|
||||
@@ -29,9 +165,9 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
struct list *source_pvl,
|
||||
struct logical_volume *lv,
|
||||
struct list *allocatable_pvs,
|
||||
alloc_policy_t alloc,
|
||||
struct list *lvs_changed)
|
||||
{
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
struct lv_list *lvl;
|
||||
struct pv_list *pvl;
|
||||
@@ -57,16 +193,15 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
/* Split LV segments to match PE ranges */
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_PV ||
|
||||
seg->area[s].u.pv.pv->dev != pvl->pv->dev)
|
||||
if (seg_type(seg, s) != AREA_PV ||
|
||||
seg_dev(seg, s) != pvl->pv->dev)
|
||||
continue;
|
||||
|
||||
/* Do these PEs need moving? */
|
||||
list_iterate_items(per, pvl->pe_ranges) {
|
||||
pe_start = seg->area[s].u.pv.pe;
|
||||
pe_start = seg_pe(seg, s);
|
||||
pe_end = pe_start + seg->area_len - 1;
|
||||
per_end = per->start + per->count - 1;
|
||||
|
||||
@@ -75,7 +210,7 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
(pe_start > per_end))
|
||||
continue;
|
||||
|
||||
if (seg->segtype->flags & SEG_AREAS_STRIPED)
|
||||
if (seg_is_striped(seg))
|
||||
stripe_multiplier = seg->area_count;
|
||||
else
|
||||
stripe_multiplier = 1;
|
||||
@@ -102,14 +237,13 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
/* Work through all segments on the supplied PV */
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_PV ||
|
||||
seg->area[s].u.pv.pv->dev != pvl->pv->dev)
|
||||
if (seg_type(seg, s) != AREA_PV ||
|
||||
seg_dev(seg, s) != pvl->pv->dev)
|
||||
continue;
|
||||
|
||||
pe_start = seg->area[s].u.pv.pe;
|
||||
pe_start = seg_pe(seg, s);
|
||||
|
||||
/* Do these PEs need moving? */
|
||||
list_iterate_items(per, pvl->pe_ranges) {
|
||||
@@ -121,8 +255,9 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
|
||||
log_debug("Matched PE range %u-%u against "
|
||||
"%s %u len %u", per->start, per_end,
|
||||
dev_name(seg->area[s].u.pv.pv->dev),
|
||||
seg->area[s].u.pv.pe, seg->area_len);
|
||||
dev_name(seg_dev(seg, s)),
|
||||
seg_pe(seg, s),
|
||||
seg->area_len);
|
||||
|
||||
/* First time, add LV to list of LVs affected */
|
||||
if (!lv_used) {
|
||||
@@ -137,25 +272,23 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
|
||||
log_very_verbose("Moving %s:%u-%u of %s/%s",
|
||||
dev_name(pvl->pv->dev),
|
||||
seg->area[s].u.pv.pe,
|
||||
seg->area[s].u.pv.pe +
|
||||
seg_pe(seg, s),
|
||||
seg_pe(seg, s) +
|
||||
seg->area_len - 1,
|
||||
lv->vg->name, lv->name);
|
||||
|
||||
start_le = lv_mirr->le_count;
|
||||
if (!lv_extend(lv->vg->fid, lv_mirr, segtype, 1,
|
||||
if (!lv_extend(lv_mirr, segtype, 1,
|
||||
seg->area_len, 0u, seg->area_len,
|
||||
seg->area[s].u.pv.pv,
|
||||
seg->area[s].u.pv.pe,
|
||||
seg_pv(seg, s),
|
||||
seg_pe(seg, s),
|
||||
PVMOVE, allocatable_pvs,
|
||||
lv->alloc)) {
|
||||
alloc)) {
|
||||
log_error("Unable to allocate "
|
||||
"temporary LV for pvmove.");
|
||||
return 0;
|
||||
}
|
||||
seg->area[s].type = AREA_LV;
|
||||
seg->area[s].u.lv.lv = lv_mirr;
|
||||
seg->area[s].u.lv.le = start_le;
|
||||
set_lv_segment_area_lv(seg, s, lv_mirr, start_le, 0);
|
||||
|
||||
extent_count += seg->area_len;
|
||||
|
||||
@@ -176,29 +309,27 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
int remove_pvmove_mirrors(struct volume_group *vg,
|
||||
struct logical_volume *lv_mirr)
|
||||
{
|
||||
struct list *lvh, *segh;
|
||||
struct lv_list *lvl;
|
||||
struct logical_volume *lv1;
|
||||
struct lv_segment *seg, *mir_seg;
|
||||
uint32_t s, c;
|
||||
|
||||
/* Loop through all LVs except the temporary mirror */
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv1 = list_item(lvh, struct lv_list)->lv;
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
lv1 = lvl->lv;
|
||||
if (lv1 == lv_mirr)
|
||||
continue;
|
||||
|
||||
/* Find all segments that point at the temporary mirror */
|
||||
list_iterate(segh, &lv1->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv1->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_LV ||
|
||||
seg->area[s].u.lv.lv != lv_mirr)
|
||||
if (seg_type(seg, s) != AREA_LV ||
|
||||
seg_lv(seg, s) != lv_mirr)
|
||||
continue;
|
||||
|
||||
/* Find the mirror segment pointed at */
|
||||
if (!(mir_seg = find_seg_by_le(lv_mirr,
|
||||
seg->area[s].
|
||||
u.lv.le))) {
|
||||
seg_le(seg, s)))) {
|
||||
/* FIXME Error message */
|
||||
log_error("No segment found with LE");
|
||||
return 0;
|
||||
@@ -206,10 +337,9 @@ int remove_pvmove_mirrors(struct volume_group *vg,
|
||||
|
||||
/* Check the segment params are compatible */
|
||||
/* FIXME Improve error mesg & remove restrcn */
|
||||
if ((!(mir_seg->segtype->flags
|
||||
& SEG_AREAS_MIRRORED)) ||
|
||||
if (!seg_is_mirrored(mir_seg) ||
|
||||
!(mir_seg->status & PVMOVE) ||
|
||||
mir_seg->le != seg->area[s].u.lv.le ||
|
||||
mir_seg->le != seg_le(seg, s) ||
|
||||
mir_seg->area_count != 2 ||
|
||||
mir_seg->area_len != seg->area_len) {
|
||||
log_error("Incompatible segments");
|
||||
@@ -225,9 +355,12 @@ int remove_pvmove_mirrors(struct volume_group *vg,
|
||||
else
|
||||
c = 0;
|
||||
|
||||
seg->area[s].type = AREA_PV;
|
||||
seg->area[s].u.pv.pv = mir_seg->area[c].u.pv.pv;
|
||||
seg->area[s].u.pv.pe = mir_seg->area[c].u.pv.pe;
|
||||
if (!set_lv_segment_area_pv(seg, s,
|
||||
seg_pv(mir_seg, c),
|
||||
seg_pe(mir_seg, c))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Replace mirror with old area */
|
||||
if (!
|
||||
@@ -254,16 +387,14 @@ int remove_pvmove_mirrors(struct volume_group *vg,
|
||||
|
||||
const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr)
|
||||
{
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
|
||||
list_iterate(segh, &lv_mirr->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
if (!(seg->segtype->flags & SEG_AREAS_MIRRORED))
|
||||
list_iterate_items(seg, &lv_mirr->segments) {
|
||||
if (!seg_is_mirrored(seg))
|
||||
continue;
|
||||
if (seg->area[0].type != AREA_PV)
|
||||
continue;
|
||||
return dev_name(seg->area[0].u.pv.pv->dev);
|
||||
return dev_name(seg_dev(seg, 0));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -271,16 +402,14 @@ const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr)
|
||||
|
||||
const char *get_pvmove_pvname_from_lv(struct logical_volume *lv)
|
||||
{
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
uint32_t s;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_LV)
|
||||
if (seg_type(seg, s) != AREA_LV)
|
||||
continue;
|
||||
return get_pvmove_pvname_from_lv_mirr(seg->area[s].u.lv.lv);
|
||||
return get_pvmove_pvname_from_lv_mirr(seg_lv(seg, s));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,23 +420,22 @@ struct logical_volume *find_pvmove_lv(struct volume_group *vg,
|
||||
struct device *dev,
|
||||
uint32_t lv_type)
|
||||
{
|
||||
struct list *lvh, *segh;
|
||||
struct lv_list *lvl;
|
||||
struct logical_volume *lv;
|
||||
struct lv_segment *seg;
|
||||
|
||||
/* Loop through all LVs */
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
lv = lvl->lv;
|
||||
|
||||
if (!(lv->status & lv_type))
|
||||
continue;
|
||||
|
||||
/* Check segment origins point to pvname */
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (seg->area[0].type != AREA_PV)
|
||||
continue;
|
||||
if (seg->area[0].u.pv.pv->dev != dev)
|
||||
if (seg_dev(seg, 0) != dev)
|
||||
continue;
|
||||
return lv;
|
||||
}
|
||||
@@ -334,9 +462,9 @@ struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
|
||||
struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
struct list *lvh, *segh, *lvs;
|
||||
struct list *lvs;
|
||||
struct logical_volume *lv1;
|
||||
struct lv_list *lvl;
|
||||
struct lv_list *lvl, *lvl1;
|
||||
struct lv_segment *seg;
|
||||
uint32_t s;
|
||||
|
||||
@@ -348,17 +476,16 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
list_init(lvs);
|
||||
|
||||
/* Loop through all LVs except the one supplied */
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv1 = list_item(lvh, struct lv_list)->lv;
|
||||
list_iterate_items(lvl1, &vg->lvs) {
|
||||
lv1 = lvl1->lv;
|
||||
if (lv1 == lv)
|
||||
continue;
|
||||
|
||||
/* Find whether any segment points at the supplied LV */
|
||||
list_iterate(segh, &lv1->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv1->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_LV ||
|
||||
seg->area[s].u.lv.lv != lv)
|
||||
if (seg_type(seg, s) != AREA_LV ||
|
||||
seg_lv(seg, s) != lv)
|
||||
continue;
|
||||
if (!(lvl = pool_alloc(cmd->mem, sizeof(*lvl)))) {
|
||||
log_error("lv_list alloc failed");
|
||||
@@ -379,15 +506,12 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
float copy_percent(struct logical_volume *lv_mirr)
|
||||
{
|
||||
uint32_t numerator = 0u, denominator = 0u;
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
|
||||
list_iterate(segh, &lv_mirr->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
|
||||
list_iterate_items(seg, &lv_mirr->segments) {
|
||||
denominator += seg->area_len;
|
||||
|
||||
if (seg->segtype->flags & SEG_AREAS_MIRRORED)
|
||||
if (seg_is_mirrored(seg))
|
||||
numerator += seg->extents_copied;
|
||||
else
|
||||
numerator += seg->area_len;
|
||||
|
||||
29
lib/metadata/pv_alloc.h
Normal file
29
lib/metadata/pv_alloc.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2005 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_PV_ALLOC_H
|
||||
#include "pool.h"
|
||||
|
||||
int alloc_pv_segment_whole_pv(struct pool *mem, struct physical_volume *pv);
|
||||
int peg_dup(struct pool *mem, struct list *peg_new, struct list *peg_old);
|
||||
struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv, uint32_t pe,
|
||||
uint32_t area_len,
|
||||
struct lv_segment *seg,
|
||||
uint32_t area_num);
|
||||
int pv_split_segment(struct physical_volume *pv, uint32_t pe);
|
||||
int release_pv_segment(struct pv_segment *peg, uint32_t area_reduction);
|
||||
int check_pv_segments(struct volume_group *vg);
|
||||
void merge_pv_segments(struct pv_segment *peg1, struct pv_segment *peg2);
|
||||
|
||||
#endif
|
||||
288
lib/metadata/pv_manip.c
Normal file
288
lib/metadata/pv_manip.c
Normal file
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 - 2005 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
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "pool.h"
|
||||
#include "metadata.h"
|
||||
#include "pv_alloc.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
static struct pv_segment *_alloc_pv_segment(struct pool *mem,
|
||||
struct physical_volume *pv,
|
||||
uint32_t pe, uint32_t len,
|
||||
struct lv_segment *lvseg,
|
||||
uint32_t lv_area)
|
||||
{
|
||||
struct pv_segment *peg;
|
||||
|
||||
if (!(peg = pool_zalloc(mem, sizeof(*peg)))) {
|
||||
log_error("pv_segment allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
peg->pv = pv;
|
||||
peg->pe = pe;
|
||||
peg->len = len;
|
||||
peg->lvseg = lvseg;
|
||||
peg->lv_area = lv_area;
|
||||
|
||||
list_init(&peg->list);
|
||||
|
||||
return peg;
|
||||
}
|
||||
|
||||
int alloc_pv_segment_whole_pv(struct pool *mem, struct physical_volume *pv)
|
||||
{
|
||||
struct pv_segment *peg;
|
||||
|
||||
if (!pv->pe_count)
|
||||
return 1;
|
||||
|
||||
/* FIXME Cope with holes in PVs */
|
||||
if (!(peg = _alloc_pv_segment(mem, pv, 0, pv->pe_count, NULL, 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_add(&pv->segments, &peg->list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int peg_dup(struct pool *mem, struct list *peg_new, struct list *peg_old)
|
||||
{
|
||||
struct pv_segment *peg, *pego;
|
||||
|
||||
list_init(peg_new);
|
||||
|
||||
list_iterate_items(pego, peg_old) {
|
||||
if (!(peg = _alloc_pv_segment(mem, pego->pv, pego->pe,
|
||||
pego->len, pego->lvseg,
|
||||
pego->lv_area))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
list_add(peg_new, &peg->list);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Split peg at given extent.
|
||||
* Second part is always deallocated.
|
||||
*/
|
||||
static int _pv_split_segment(struct physical_volume *pv, struct pv_segment *peg,
|
||||
uint32_t pe)
|
||||
{
|
||||
struct pv_segment *peg_new;
|
||||
|
||||
if (!(peg_new = _alloc_pv_segment(pv->fmt->cmd->mem, peg->pv, pe,
|
||||
peg->len + peg->pe - pe,
|
||||
NULL, 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
peg->len = peg->len - peg_new->len;
|
||||
|
||||
list_add_h(&peg->list, &peg_new->list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure there is a PV segment boundary at the given extent.
|
||||
*/
|
||||
int pv_split_segment(struct physical_volume *pv, uint32_t pe)
|
||||
{
|
||||
struct pv_segment *peg;
|
||||
|
||||
if (pe == pv->pe_count)
|
||||
return 1;
|
||||
|
||||
if (!(peg = find_peg_by_pe(pv, pe))) {
|
||||
log_error("Segment with extent %" PRIu32 " in PV %s not found",
|
||||
pe, dev_name(pv->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is a peg start already */
|
||||
if (pe == peg->pe)
|
||||
return 1;
|
||||
|
||||
if (!_pv_split_segment(pv, peg, pe)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct pv_segment null_pv_segment = {
|
||||
pv: NULL,
|
||||
pe: 0
|
||||
};
|
||||
|
||||
struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv,
|
||||
uint32_t pe, uint32_t area_len,
|
||||
struct lv_segment *seg,
|
||||
uint32_t area_num)
|
||||
{
|
||||
struct pv_segment *peg;
|
||||
|
||||
/* Missing format1 PV */
|
||||
if (!pv)
|
||||
return &null_pv_segment;
|
||||
|
||||
if (!pv_split_segment(pv, pe) ||
|
||||
!pv_split_segment(pv, pe + area_len)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(peg = find_peg_by_pe(pv, pe))) {
|
||||
log_error("Missing PV segment on %s at %u.",
|
||||
dev_name(pv->dev), pe);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
peg->lvseg = seg;
|
||||
peg->lv_area = area_num;
|
||||
|
||||
return peg;
|
||||
}
|
||||
|
||||
int release_pv_segment(struct pv_segment *peg, uint32_t area_reduction)
|
||||
{
|
||||
peg->pv->pe_alloc_count -= area_reduction;
|
||||
|
||||
if (!peg->lvseg->area_len) {
|
||||
peg->lvseg = NULL;
|
||||
peg->lv_area = 0;
|
||||
|
||||
/* FIXME merge free space */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!pv_split_segment(peg->pv, peg->pe + peg->lvseg->area_len)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only for use by lv_segment merging routines.
|
||||
*/
|
||||
void merge_pv_segments(struct pv_segment *peg1, struct pv_segment *peg2)
|
||||
{
|
||||
peg1->len += peg2->len;
|
||||
|
||||
list_del(&peg2->list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check all pv_segments in VG for consistency
|
||||
*/
|
||||
int check_pv_segments(struct volume_group *vg)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
struct pv_list *pvl;
|
||||
struct pv_segment *peg;
|
||||
unsigned s, segno;
|
||||
uint32_t start_pe, alloced;
|
||||
uint32_t pv_count = 0, free_count = 0, extent_count = 0;
|
||||
int ret = 1;
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
pv = pvl->pv;
|
||||
segno = 0;
|
||||
start_pe = 0;
|
||||
alloced = 0;
|
||||
pv_count++;
|
||||
|
||||
list_iterate_items(peg, &pv->segments) {
|
||||
s = peg->lv_area;
|
||||
|
||||
/* FIXME Remove this next line eventually */
|
||||
log_debug("%s %u: %6u %6u: %s(%u:%u)",
|
||||
dev_name(pv->dev), segno++, peg->pe, peg->len,
|
||||
peg->lvseg ? peg->lvseg->lv->name : "NULL",
|
||||
peg->lvseg ? peg->lvseg->le : 0, s);
|
||||
/* FIXME Add details here on failure instead */
|
||||
if (start_pe != peg->pe) {
|
||||
log_error("Gap in pvsegs: %u, %u",
|
||||
start_pe, peg->pe);
|
||||
ret = 0;
|
||||
}
|
||||
if (peg->lvseg) {
|
||||
if (seg_type(peg->lvseg, s) != AREA_PV) {
|
||||
log_error("Wrong lvseg area type");
|
||||
ret = 0;
|
||||
}
|
||||
if (seg_pvseg(peg->lvseg, s) != peg) {
|
||||
log_error("Inconsistent pvseg pointers");
|
||||
ret = 0;
|
||||
}
|
||||
if (peg->lvseg->area_len != peg->len) {
|
||||
log_error("Inconsistent length: %u %u",
|
||||
peg->len,
|
||||
peg->lvseg->area_len);
|
||||
ret = 0;
|
||||
}
|
||||
alloced += peg->len;
|
||||
}
|
||||
start_pe += peg->len;
|
||||
}
|
||||
|
||||
if (start_pe != pv->pe_count) {
|
||||
log_error("PV segment pe_count mismatch: %u != %u",
|
||||
start_pe, pv->pe_count);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (alloced != pv->pe_alloc_count) {
|
||||
log_error("PV segment pe_alloc_count mismatch: "
|
||||
"%u != %u", alloced, pv->pe_alloc_count);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
extent_count += start_pe;
|
||||
free_count += (start_pe - alloced);
|
||||
}
|
||||
|
||||
if (pv_count != vg->pv_count) {
|
||||
log_error("PV segment VG pv_count mismatch: %u != %u",
|
||||
pv_count, vg->pv_count);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (free_count != vg->free_count) {
|
||||
log_error("PV segment VG free_count mismatch: %u != %u",
|
||||
free_count, vg->free_count);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (extent_count != vg->extent_count) {
|
||||
log_error("PV segment VG extent_count mismatch: %u != %u",
|
||||
extent_count, vg->extent_count);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -16,16 +16,121 @@
|
||||
#include "lib.h"
|
||||
#include "pv_map.h"
|
||||
#include "hash.h"
|
||||
#include "pv_alloc.h"
|
||||
|
||||
static int _create_maps(struct pool *mem, struct list *pvs, struct list *maps)
|
||||
/*
|
||||
* Areas are maintained in size order, largest first.
|
||||
*/
|
||||
static void _insert_area(struct list *head, struct pv_area *a)
|
||||
{
|
||||
struct pv_area *pva;
|
||||
|
||||
list_iterate_items(pva, head) {
|
||||
if (a->count > pva->count)
|
||||
break;
|
||||
}
|
||||
|
||||
list_add(&pva->list, &a->list);
|
||||
}
|
||||
|
||||
static int _create_single_area(struct pool *mem, struct pv_map *pvm,
|
||||
uint32_t start, uint32_t length)
|
||||
{
|
||||
struct pv_area *pva;
|
||||
|
||||
if (!(pva = pool_zalloc(mem, sizeof(*pva)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("Allowing allocation on %s start PE %" PRIu32 " length %"
|
||||
PRIu32, dev_name(pvm->pv->dev), start, length);
|
||||
pva->map = pvm;
|
||||
pva->start = start;
|
||||
pva->count = length;
|
||||
_insert_area(&pvm->areas, pva);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _create_alloc_areas_for_pv(struct pool *mem, struct pv_map *pvm,
|
||||
uint32_t start, uint32_t count)
|
||||
{
|
||||
struct pv_segment *peg;
|
||||
uint32_t pe, end, area_len;
|
||||
|
||||
/* Only select extents from start to end inclusive */
|
||||
end = start + count - 1;
|
||||
if (end > pvm->pv->pe_count - 1)
|
||||
end = pvm->pv->pe_count - 1;
|
||||
|
||||
pe = start;
|
||||
|
||||
/* Walk through complete ordered list of device segments */
|
||||
list_iterate_items(peg, &pvm->pv->segments) {
|
||||
/* pe holds the next extent we want to check */
|
||||
|
||||
/* Beyond the range we're interested in? */
|
||||
if (pe > end)
|
||||
break;
|
||||
|
||||
/* Skip if we haven't reached the first seg we want yet */
|
||||
if (pe > peg->pe + peg->len - 1)
|
||||
continue;
|
||||
|
||||
/* Free? */
|
||||
if (peg->lvseg)
|
||||
goto next;
|
||||
|
||||
/* How much of this peg do we need? */
|
||||
area_len = (end >= peg->pe + peg->len - 1) ?
|
||||
peg->len - (pe - peg->pe) : end - pe + 1;
|
||||
|
||||
if (!_create_single_area(mem, pvm, pe, area_len)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
next:
|
||||
pe = peg->pe + peg->len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _create_all_areas_for_pv(struct pool *mem, struct pv_map *pvm,
|
||||
struct list *pe_ranges)
|
||||
{
|
||||
struct pe_range *aa;
|
||||
|
||||
if (!pe_ranges) {
|
||||
/* Use whole PV */
|
||||
if (!_create_alloc_areas_for_pv(mem, pvm, UINT32_C(0),
|
||||
pvm->pv->pe_count)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
list_iterate_items(aa, pe_ranges) {
|
||||
if (!_create_alloc_areas_for_pv(mem, pvm, aa->start,
|
||||
aa->count)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _create_maps(struct pool *mem, struct list *pvs, struct list *pvms)
|
||||
{
|
||||
struct list *tmp;
|
||||
struct pv_map *pvm;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate(tmp, pvs) {
|
||||
pvl = list_item(tmp, struct pv_list);
|
||||
|
||||
list_iterate_items(pvl, pvs) {
|
||||
if (!(pvl->pv->status & ALLOCATABLE_PV))
|
||||
continue;
|
||||
|
||||
@@ -34,255 +139,43 @@ static int _create_maps(struct pool *mem, struct list *pvs, struct list *maps)
|
||||
return 0;
|
||||
}
|
||||
|
||||
pvm->pvl = pvl;
|
||||
if (!(pvm->allocated_extents =
|
||||
bitset_create(mem, pvl->pv->pe_count))) {
|
||||
pvm->pv = pvl->pv;
|
||||
|
||||
list_init(&pvm->areas);
|
||||
list_add(pvms, &pvm->list);
|
||||
|
||||
if (!_create_all_areas_for_pv(mem, pvm, pvl->pe_ranges)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_init(&pvm->areas);
|
||||
list_add(maps, &pvm->list);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _set_allocd(struct hash_table *hash,
|
||||
struct physical_volume *pv, uint32_t pe)
|
||||
{
|
||||
struct pv_map *pvm;
|
||||
|
||||
if (!(pvm = (struct pv_map *) hash_lookup(hash, dev_name(pv->dev)))) {
|
||||
/*
|
||||
* it doesn't matter that this fails, it just
|
||||
* means this part of the lv is on a pv that
|
||||
* we're not interested in allocating to.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* sanity check */
|
||||
if (bit(pvm->allocated_extents, pe)) {
|
||||
log_error("Physical extent %d of %s referenced by more than "
|
||||
"one logical volume", pe, dev_name(pv->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
bit_set(pvm->allocated_extents, pe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _fill_bitsets(struct volume_group *vg, struct list *maps)
|
||||
{
|
||||
struct list *lvh, *pvmh, *segh;
|
||||
struct logical_volume *lv;
|
||||
struct pv_map *pvm;
|
||||
uint32_t s, pe;
|
||||
struct hash_table *hash;
|
||||
struct lv_segment *seg;
|
||||
int r = 0;
|
||||
|
||||
if (!(hash = hash_create(128))) {
|
||||
log_err("Couldn't create hash table for pv maps.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* populate the hash table */
|
||||
list_iterate(pvmh, maps) {
|
||||
pvm = list_item(pvmh, struct pv_map);
|
||||
if (!hash_insert(hash, dev_name(pvm->pvl->pv->dev), pvm)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* iterate through all the lv's setting bit's for used pe's */
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
|
||||
for (s = 0u; s < seg->area_count; s++) {
|
||||
for (pe = 0u; pe < seg->area_len; pe++) {
|
||||
if (seg->area[s].type != AREA_PV)
|
||||
continue;
|
||||
if (!_set_allocd(hash,
|
||||
seg->area[s].u.pv.pv,
|
||||
seg->area[s].u.pv.pe
|
||||
+ pe)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
hash_destroy(hash);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Areas are maintained in size order.
|
||||
* Create list of PV areas available for this particular allocation
|
||||
*/
|
||||
static void _insert_area(struct list *head, struct pv_area *a)
|
||||
{
|
||||
struct list *pvah;
|
||||
struct pv_area *pva = NULL;
|
||||
|
||||
if (list_empty(head)) {
|
||||
list_add(head, &a->list);
|
||||
return;
|
||||
}
|
||||
|
||||
list_iterate(pvah, head) {
|
||||
pva = list_item(pvah, struct pv_area);
|
||||
|
||||
if (pva->count < a->count)
|
||||
break;
|
||||
}
|
||||
|
||||
list_add_h(&pva->list, &a->list);
|
||||
}
|
||||
|
||||
static int _create_single_area(struct pool *mem, struct pv_map *pvm,
|
||||
uint32_t end, uint32_t *extent)
|
||||
{
|
||||
uint32_t e = *extent, b;
|
||||
struct pv_area *pva;
|
||||
|
||||
while (e <= end && bit(pvm->allocated_extents, e))
|
||||
e++;
|
||||
|
||||
if (e > end) {
|
||||
*extent = e;
|
||||
return 1;
|
||||
}
|
||||
|
||||
b = e++;
|
||||
|
||||
while (e <= end && !bit(pvm->allocated_extents, e))
|
||||
e++;
|
||||
|
||||
if (!(pva = pool_zalloc(mem, sizeof(*pva)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("Allowing allocation on %s start PE %" PRIu32 " length %"
|
||||
PRIu32, dev_name(pvm->pvl->pv->dev), b, e - b);
|
||||
pva->map = pvm;
|
||||
pva->start = b;
|
||||
pva->count = e - b;
|
||||
_insert_area(&pvm->areas, pva);
|
||||
*extent = e;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _create_areas(struct pool *mem, struct pv_map *pvm, uint32_t start,
|
||||
uint32_t count)
|
||||
{
|
||||
uint32_t pe, end;
|
||||
|
||||
end = start + count - 1;
|
||||
if (end > pvm->pvl->pv->pe_count - 1)
|
||||
end = pvm->pvl->pv->pe_count - 1;
|
||||
|
||||
pe = start;
|
||||
while (pe <= end)
|
||||
if (!_create_single_area(mem, pvm, end, &pe)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _create_allocatable_areas(struct pool *mem, struct pv_map *pvm)
|
||||
{
|
||||
struct list *alloc_areas, *aah;
|
||||
struct pe_range *aa;
|
||||
|
||||
alloc_areas = pvm->pvl->pe_ranges;
|
||||
|
||||
if (alloc_areas) {
|
||||
list_iterate(aah, alloc_areas) {
|
||||
aa = list_item(aah, struct pe_range);
|
||||
if (!_create_areas(mem, pvm, aa->start, aa->count)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
/* Use whole PV */
|
||||
if (!_create_areas(mem, pvm, UINT32_C(0),
|
||||
pvm->pvl->pv->pe_count)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _create_all_areas(struct pool *mem, struct list *maps,
|
||||
struct list *pvs)
|
||||
{
|
||||
struct list *tmp;
|
||||
struct pv_map *pvm;
|
||||
|
||||
list_iterate(tmp, maps) {
|
||||
pvm = list_item(tmp, struct pv_map);
|
||||
|
||||
if (!_create_allocatable_areas(mem, pvm)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct list *create_pv_maps(struct pool *mem, struct volume_group *vg,
|
||||
struct list *pvs)
|
||||
struct list *allocatable_pvs)
|
||||
{
|
||||
struct list *maps = pool_zalloc(mem, sizeof(*maps));
|
||||
struct list *pvms;
|
||||
|
||||
if (!maps) {
|
||||
stack;
|
||||
if (!(pvms = pool_zalloc(mem, sizeof(*pvms)))) {
|
||||
log_error("create_pv_maps alloc failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(maps);
|
||||
list_init(pvms);
|
||||
|
||||
if (!_create_maps(mem, pvs, maps)) {
|
||||
if (!_create_maps(mem, allocatable_pvs, pvms)) {
|
||||
log_error("Couldn't create physical volume maps in %s",
|
||||
vg->name);
|
||||
goto bad;
|
||||
pool_free(mem, pvms);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_fill_bitsets(vg, maps)) {
|
||||
log_error("Couldn't fill extent allocation bitmaps in %s",
|
||||
vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_create_all_areas(mem, maps, pvs)) {
|
||||
log_error("Couldn't create area maps in %s", vg->name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
return maps;
|
||||
|
||||
bad:
|
||||
pool_free(mem, maps);
|
||||
return NULL;
|
||||
return pvms;
|
||||
}
|
||||
|
||||
void consume_pv_area(struct pv_area *pva, uint32_t to_go)
|
||||
|
||||
@@ -33,19 +33,21 @@ struct pv_area {
|
||||
uint32_t start;
|
||||
uint32_t count;
|
||||
|
||||
struct list list;
|
||||
struct list list; /* pv_map.areas */
|
||||
};
|
||||
|
||||
struct pv_map {
|
||||
struct pv_list *pvl;
|
||||
bitset_t allocated_extents;
|
||||
struct list areas;
|
||||
struct physical_volume *pv;
|
||||
struct list areas; /* struct pv_areas */
|
||||
|
||||
struct list list;
|
||||
};
|
||||
|
||||
struct list *create_pv_maps(struct pool *mem,
|
||||
struct volume_group *vg, struct list *pvs);
|
||||
/*
|
||||
* Find intersection between available_pvs and free space in VG
|
||||
*/
|
||||
struct list *create_pv_maps(struct pool *mem, struct volume_group *vg,
|
||||
struct list *allocatable_pvs);
|
||||
|
||||
void consume_pv_area(struct pv_area *area, uint32_t to_go);
|
||||
|
||||
|
||||
@@ -33,6 +33,16 @@ struct dev_manager;
|
||||
#define SEG_FORMAT1_SUPPORT 0x00000010
|
||||
#define SEG_VIRTUAL 0x00000020
|
||||
|
||||
#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)
|
||||
#define seg_is_snapshot(seg) ((seg)->segtype->flags & SEG_SNAPSHOT ? 1 : 0)
|
||||
#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 segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
|
||||
#define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
|
||||
#define segtype_is_virtual(segtype) ((segtype)->flags & SEG_VIRTUAL ? 1 : 0)
|
||||
|
||||
struct segment_type {
|
||||
struct list list;
|
||||
struct cmd_context *cmd;
|
||||
|
||||
@@ -16,101 +16,31 @@
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "toolcontext.h"
|
||||
#include "lv_alloc.h"
|
||||
|
||||
int lv_is_origin(const struct logical_volume *lv)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot *s;
|
||||
|
||||
list_iterate(slh, &lv->vg->snapshots) {
|
||||
s = list_item(slh, struct snapshot_list)->snapshot;
|
||||
if (s->origin == lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return lv->origin_count ? 1 : 0;
|
||||
}
|
||||
|
||||
int lv_is_cow(const struct logical_volume *lv)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot *s;
|
||||
|
||||
list_iterate(slh, &lv->vg->snapshots) {
|
||||
s = list_item(slh, struct snapshot_list)->snapshot;
|
||||
if (s->cow == lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return lv->snapshot ? 1 : 0;
|
||||
}
|
||||
|
||||
struct snapshot *find_origin(const struct logical_volume *lv)
|
||||
/* Given a cow LV, return the snapshot lv_segment that uses it */
|
||||
struct lv_segment *find_cow(const struct logical_volume *lv)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot *s;
|
||||
|
||||
list_iterate(slh, &lv->vg->snapshots) {
|
||||
s = list_item(slh, struct snapshot_list)->snapshot;
|
||||
if (s->origin == lv)
|
||||
return s;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return lv->snapshot;
|
||||
}
|
||||
|
||||
struct snapshot *find_cow(const struct logical_volume *lv)
|
||||
int vg_add_snapshot(struct format_instance *fid, const char *name,
|
||||
struct logical_volume *origin,
|
||||
struct logical_volume *cow, union lvid *lvid,
|
||||
uint32_t extent_count, uint32_t chunk_size)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot *s;
|
||||
|
||||
list_iterate(slh, &lv->vg->snapshots) {
|
||||
s = list_item(slh, struct snapshot_list)->snapshot;
|
||||
if (s->cow == lv)
|
||||
return s;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct list *find_snapshots(const struct logical_volume *lv)
|
||||
{
|
||||
struct list *slh;
|
||||
struct list *snaplist;
|
||||
struct snapshot *s;
|
||||
struct snapshot_list *newsl;
|
||||
struct pool *mem = lv->vg->cmd->mem;
|
||||
|
||||
if (!(snaplist = pool_alloc(mem, sizeof(*snaplist)))) {
|
||||
log_error("snapshot name list allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(snaplist);
|
||||
|
||||
list_iterate(slh, &lv->vg->snapshots) {
|
||||
s = list_item(slh, struct snapshot_list)->snapshot;
|
||||
if (!(s->origin == lv))
|
||||
continue;
|
||||
if (!(newsl = pool_alloc(mem, sizeof(*newsl)))) {
|
||||
log_error("snapshot_list structure allocation failed");
|
||||
pool_free(mem, snaplist);
|
||||
return NULL;
|
||||
}
|
||||
newsl->snapshot = s;
|
||||
list_add(snaplist, &newsl->list);
|
||||
}
|
||||
|
||||
return snaplist;
|
||||
}
|
||||
|
||||
int vg_add_snapshot(struct logical_volume *origin,
|
||||
struct logical_volume *cow,
|
||||
int persistent, struct id *id, uint32_t chunk_size)
|
||||
{
|
||||
struct snapshot *s;
|
||||
struct snapshot_list *sl;
|
||||
struct pool *mem = origin->vg->cmd->mem;
|
||||
struct logical_volume *snap;
|
||||
struct lv_segment *seg;
|
||||
|
||||
/*
|
||||
* Is the cow device already being used ?
|
||||
@@ -120,53 +50,53 @@ int vg_add_snapshot(struct logical_volume *origin,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(s = pool_alloc(mem, sizeof(*s)))) {
|
||||
if (!(snap = lv_create_empty(fid, name ? name : "snapshot%d",
|
||||
lvid, LVM_READ | LVM_WRITE | VISIBLE_LV,
|
||||
ALLOC_INHERIT, 1, origin->vg))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s->persistent = persistent;
|
||||
s->chunk_size = chunk_size;
|
||||
s->origin = origin;
|
||||
s->cow = cow;
|
||||
snap->le_count = extent_count;
|
||||
|
||||
if (id)
|
||||
s->id = *id;
|
||||
else if (!id_create(&s->id)) {
|
||||
log_error("Snapshot UUID creation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sl = pool_alloc(mem, sizeof(*sl)))) {
|
||||
if (!(seg = alloc_snapshot_seg(snap, 0, 0))) {
|
||||
stack;
|
||||
pool_free(mem, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->chunk_size = chunk_size;
|
||||
seg->origin = origin;
|
||||
seg->cow = cow;
|
||||
seg->lv->status |= SNAPSHOT;
|
||||
|
||||
origin->origin_count++;
|
||||
origin->vg->snapshot_count++;
|
||||
origin->vg->lv_count--;
|
||||
cow->snapshot = seg;
|
||||
|
||||
cow->status &= ~VISIBLE_LV;
|
||||
sl->snapshot = s;
|
||||
list_add(&origin->vg->snapshots, &sl->list);
|
||||
origin->vg->snapshot_count++;
|
||||
|
||||
list_add(&origin->snapshot_segs, &seg->origin_list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow)
|
||||
int vg_remove_snapshot(struct logical_volume *cow)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot_list *sl;
|
||||
list_del(&cow->snapshot->origin_list);
|
||||
cow->snapshot->origin->origin_count--;
|
||||
|
||||
list_iterate(slh, &vg->snapshots) {
|
||||
sl = list_item(slh, struct snapshot_list);
|
||||
|
||||
if (sl->snapshot->cow == cow) {
|
||||
list_del(slh);
|
||||
vg->snapshot_count--;
|
||||
return 1;
|
||||
}
|
||||
if (!lv_remove(cow->snapshot->lv)) {
|
||||
log_error("Failed to remove internal snapshot LV %s",
|
||||
cow->snapshot->lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fail */
|
||||
log_err("Asked to remove an unknown snapshot.");
|
||||
return 0;
|
||||
cow->snapshot = NULL;
|
||||
|
||||
cow->vg->snapshot_count--;
|
||||
cow->vg->lv_count++;
|
||||
cow->status |= VISIBLE_LV;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ enum {
|
||||
};
|
||||
|
||||
struct mirror_state {
|
||||
uint32_t region_size;
|
||||
uint32_t default_region_size;
|
||||
};
|
||||
|
||||
static const char *_name(const struct lv_segment *seg)
|
||||
@@ -45,14 +45,25 @@ static const char *_name(const struct lv_segment *seg)
|
||||
|
||||
static void _display(const struct lv_segment *seg)
|
||||
{
|
||||
const char *size;
|
||||
|
||||
log_print(" Mirrors\t\t%u", seg->area_count);
|
||||
log_print(" Mirror size\t\t%u", seg->area_len);
|
||||
if (seg->log_lv)
|
||||
log_print(" Mirror log volume\t%s", seg->log_lv->name);
|
||||
|
||||
if (seg->region_size) {
|
||||
size = display_size(seg->lv->vg->cmd,
|
||||
(uint64_t) seg->region_size,
|
||||
SIZE_SHORT);
|
||||
log_print(" Mirror region size\t%s", size);
|
||||
}
|
||||
|
||||
log_print(" Mirror original:");
|
||||
display_stripe(seg, 0, " ");
|
||||
log_print(" Mirror destination:");
|
||||
display_stripe(seg, 1, " ");
|
||||
log_print(" ");
|
||||
|
||||
}
|
||||
|
||||
static int _text_import_area_count(struct config_node *sn, uint32_t *area_count)
|
||||
@@ -70,6 +81,7 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn,
|
||||
struct hash_table *pv_hash)
|
||||
{
|
||||
const struct config_node *cn;
|
||||
char *logname = NULL;
|
||||
|
||||
if (find_config_node(sn, "extents_moved")) {
|
||||
if (get_config_uint32(sn, "extents_moved",
|
||||
@@ -82,13 +94,42 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn,
|
||||
}
|
||||
}
|
||||
|
||||
if (find_config_node(sn, "region_size")) {
|
||||
if (!get_config_uint32(sn, "region_size",
|
||||
&seg->region_size)) {
|
||||
log_error("Couldn't read 'region_size' for "
|
||||
"segment '%s'.", sn->key);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((cn = find_config_node(sn, "mirror_log"))) {
|
||||
if (!cn->v || !cn->v->v.str) {
|
||||
log_error("Mirror log type must be a string.");
|
||||
return 0;
|
||||
}
|
||||
logname = cn->v->v.str;
|
||||
if (!(seg->log_lv = find_lv(seg->lv->vg, logname))) {
|
||||
log_error("Unrecognised mirror log in segment %s.",
|
||||
sn->key);
|
||||
return 0;
|
||||
}
|
||||
seg->log_lv->status |= MIRROR_LOG;
|
||||
}
|
||||
|
||||
if (logname && !seg->region_size) {
|
||||
log_error("Missing region size for mirror log for segment "
|
||||
"'%s'.", sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(sn, "mirrors"))) {
|
||||
log_error("Couldn't find mirrors array for segment "
|
||||
"'%s'.", sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return text_import_areas(seg, sn, cn, pv_hash);
|
||||
return text_import_areas(seg, sn, cn, pv_hash, MIRROR_IMAGE);
|
||||
}
|
||||
|
||||
static int _text_export(const struct lv_segment *seg, struct formatter *f)
|
||||
@@ -96,7 +137,11 @@ static int _text_export(const struct lv_segment *seg, struct formatter *f)
|
||||
outf(f, "mirror_count = %u", seg->area_count);
|
||||
if (seg->status & PVMOVE)
|
||||
out_size(f, (uint64_t) seg->extents_copied * seg->lv->vg->extent_size,
|
||||
"extents_moved = %u", seg->extents_copied);
|
||||
"extents_moved = %" PRIu32, seg->extents_copied);
|
||||
if (seg->log_lv)
|
||||
outf(f, "mirror_log = \"%s\"", seg->log_lv->name);
|
||||
if (seg->region_size)
|
||||
outf(f, "region_size = %" PRIu32, seg->region_size);
|
||||
|
||||
return out_areas(f, seg, "mirror");
|
||||
}
|
||||
@@ -112,7 +157,7 @@ static struct mirror_state *_init_target(struct pool *mem,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mirr_state->region_size = 2 *
|
||||
mirr_state->default_region_size = 2 *
|
||||
find_config_int(cft->root,
|
||||
"activation/mirror_region_size",
|
||||
DEFAULT_MIRROR_REGION_SIZE);
|
||||
@@ -131,6 +176,7 @@ static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
|
||||
int areas = seg->area_count;
|
||||
int start_area = 0u;
|
||||
uint32_t region_size, region_max;
|
||||
int ret;
|
||||
|
||||
if (!*target_state)
|
||||
*target_state = _init_target(mem, cft);
|
||||
@@ -155,21 +201,29 @@ static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
|
||||
} else {
|
||||
*target = "mirror";
|
||||
|
||||
/* Find largest power of 2 region size unit we can use */
|
||||
region_max = (1 << (ffs(seg->area_len) - 1)) *
|
||||
if (!(seg->status & PVMOVE)) {
|
||||
if (!seg->region_size) {
|
||||
log_error("Missing region size for mirror segment.");
|
||||
return 0;
|
||||
}
|
||||
region_size = seg->region_size;
|
||||
} else {
|
||||
/* Find largest power of 2 region size unit we can use */
|
||||
region_max = (1 << (ffs(seg->area_len) - 1)) *
|
||||
seg->lv->vg->extent_size;
|
||||
|
||||
region_size = mirr_state->region_size;
|
||||
if (region_max < region_size) {
|
||||
region_size = region_max;
|
||||
log_verbose("Using reduced mirror region size of %u sectors",
|
||||
region_size);
|
||||
region_size = mirr_state->default_region_size;
|
||||
if (region_max < region_size) {
|
||||
region_size = region_max;
|
||||
log_verbose("Using reduced mirror region size of %u sectors",
|
||||
region_size);
|
||||
}
|
||||
}
|
||||
|
||||
if ((*pos = lvm_snprintf(params, paramsize, "core 1 %u %u ",
|
||||
region_size, areas)) < 0) {
|
||||
if ((ret = compose_log_line(dm, seg, params, paramsize, pos,
|
||||
areas, region_size)) <= 0) {
|
||||
stack;
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,11 @@ int lvm_rename(const char *old, const char *new)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
link(old, new);
|
||||
if (link(old, new)) {
|
||||
log_error("%s: rename to %s failed: %s", old, new,
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stat(old, &buf)) {
|
||||
log_sys_error("stat", old);
|
||||
@@ -148,7 +152,8 @@ static int _create_dir_recursive(const char *dir)
|
||||
if (*orig) {
|
||||
rc = mkdir(orig, 0777);
|
||||
if (rc < 0 && errno != EEXIST) {
|
||||
log_sys_error("mkdir", orig);
|
||||
if (errno != EROFS)
|
||||
log_sys_error("mkdir", orig);
|
||||
dbg_free(orig);
|
||||
return 0;
|
||||
}
|
||||
@@ -160,7 +165,8 @@ static int _create_dir_recursive(const char *dir)
|
||||
/* Create final directory */
|
||||
rc = mkdir(dir, 0777);
|
||||
if (rc < 0 && errno != EEXIST) {
|
||||
log_sys_error("mkdir", dir);
|
||||
if (errno != EROFS)
|
||||
log_sys_error("mkdir", dir);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
@@ -22,7 +22,6 @@ int set_selinux_context(const char *path)
|
||||
{
|
||||
security_context_t scontext;
|
||||
|
||||
log_very_verbose("Setting SELinux context for %s", path);
|
||||
if (is_selinux_enabled() <= 0)
|
||||
return 1;
|
||||
|
||||
@@ -31,6 +30,9 @@ int set_selinux_context(const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Setting SELinux context for %s to %s",
|
||||
path, scontext);
|
||||
|
||||
if ((lsetfilecon(path, scontext) < 0) && (errno != ENOTSUP)) {
|
||||
log_sys_error("lsetfilecon", path);
|
||||
free(scontext);
|
||||
|
||||
@@ -19,6 +19,16 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
char *dbg_strdup(const char *str)
|
||||
{
|
||||
char *ret = dbg_malloc(strlen(str) + 1);
|
||||
|
||||
if (ret)
|
||||
strcpy(ret, str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEM
|
||||
|
||||
struct memblock {
|
||||
@@ -48,13 +58,14 @@ void *malloc_aux(size_t s, const char *file, int line)
|
||||
size_t tsize = s + sizeof(*nb) + sizeof(unsigned long);
|
||||
|
||||
if (s > 50000000) {
|
||||
log_error("Huge memory allocation (size %" PRIuPTR
|
||||
log_error("Huge memory allocation (size %" PRIsize_t
|
||||
") rejected - metadata corruption?", s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(nb = malloc(tsize))) {
|
||||
log_error("couldn't allocate any memory, size = %" PRIuPTR, s);
|
||||
log_error("couldn't allocate any memory, size = %" PRIsize_t,
|
||||
s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -101,6 +112,9 @@ void *malloc_aux(size_t s, const char *file, int line)
|
||||
if (_mem_stats.bytes > _mem_stats.mbytes)
|
||||
_mem_stats.mbytes = _mem_stats.bytes;
|
||||
|
||||
/* log_debug("Allocated: %u %u %u", nb->id, _mem_stats.blocks_allocated,
|
||||
_mem_stats.bytes); */
|
||||
|
||||
return nb + 1;
|
||||
}
|
||||
|
||||
@@ -182,6 +196,8 @@ int dump_memory(void)
|
||||
for (c = 0; c < sizeof(str) - 1; c++) {
|
||||
if (c >= mb->length)
|
||||
str[c] = ' ';
|
||||
else if (*(char *)(mb->magic + c) == '\0')
|
||||
str[c] = '\0';
|
||||
else if (*(char *)(mb->magic + c) < ' ')
|
||||
str[c] = '?';
|
||||
else
|
||||
@@ -190,7 +206,7 @@ int dump_memory(void)
|
||||
str[sizeof(str) - 1] = '\0';
|
||||
|
||||
print_log(_LOG_INFO, mb->file, mb->line,
|
||||
"block %d at %p, size %" PRIdPTR "\t [%s]",
|
||||
"block %d at %p, size %" PRIsize_t "\t [%s]",
|
||||
mb->id, mb->magic, mb->length, str);
|
||||
tot += mb->length;
|
||||
}
|
||||
@@ -220,7 +236,7 @@ void bounds_check(void)
|
||||
void *malloc_aux(size_t s, const char *file, int line)
|
||||
{
|
||||
if (s > 50000000) {
|
||||
log_error("Huge memory allocation (size %" PRIuPTR
|
||||
log_error("Huge memory allocation (size %" PRIsize_t
|
||||
") rejected - metadata corruption?", s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
#include <string.h>
|
||||
|
||||
void *malloc_aux(size_t s, const char *file, int line);
|
||||
# define dbg_malloc(s) malloc_aux((s), __FILE__, __LINE__)
|
||||
#define dbg_malloc(s) malloc_aux((s), __FILE__, __LINE__)
|
||||
|
||||
char *dbg_strdup(const char *str);
|
||||
|
||||
#ifdef DEBUG_MEM
|
||||
|
||||
@@ -42,14 +44,4 @@ void bounds_check(void);
|
||||
|
||||
#endif
|
||||
|
||||
static inline char *dbg_strdup(const char *str)
|
||||
{
|
||||
char *ret = dbg_malloc(strlen(str) + 1);
|
||||
|
||||
if (ret)
|
||||
strcpy(ret, str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,14 +27,14 @@
|
||||
((x) & 0xff000000U) >> 24 | \
|
||||
((x) & 0x0000ff00U) << 8 | \
|
||||
((x) & 0x00ff0000U) >> 8)
|
||||
# define bswap_64(x) (((x) & 0x00000000000000ffU) << 56 | \
|
||||
((x) & 0xff00000000000000U) >> 56 | \
|
||||
((x) & 0x000000000000ff00U) << 40 | \
|
||||
((x) & 0x00ff000000000000U) >> 40 | \
|
||||
((x) & 0x0000000000ff0000U) << 24 | \
|
||||
((x) & 0x0000ff0000000000U) >> 24 | \
|
||||
((x) & 0x00000000ff000000U) << 8 | \
|
||||
((x) & 0x000000ff00000000U) >> 8)
|
||||
# define bswap_64(x) (((x) & 0x00000000000000ffULL) << 56 | \
|
||||
((x) & 0xff00000000000000ULL) >> 56 | \
|
||||
((x) & 0x000000000000ff00ULL) << 40 | \
|
||||
((x) & 0x00ff000000000000ULL) >> 40 | \
|
||||
((x) & 0x0000000000ff0000ULL) << 24 | \
|
||||
((x) & 0x0000ff0000000000ULL) >> 24 | \
|
||||
((x) & 0x00000000ff000000ULL) << 8 | \
|
||||
((x) & 0x000000ff00000000ULL) >> 8)
|
||||
#endif
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid")
|
||||
FIELD(LVS, lv, STR, "LV", name, 4, string, "lv_name")
|
||||
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")
|
||||
@@ -32,6 +32,7 @@ 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(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
|
||||
FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
|
||||
@@ -67,8 +68,12 @@ 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, "Chunk", chunk_size, 5, size32, "chunksize")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize")
|
||||
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(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start")
|
||||
FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size")
|
||||
/* *INDENT-ON* */
|
||||
|
||||
@@ -31,6 +31,7 @@ static union {
|
||||
struct logical_volume _lv;
|
||||
struct volume_group _vg;
|
||||
struct lv_segment _seg;
|
||||
struct pv_segment _pvseg;
|
||||
} _dummy;
|
||||
|
||||
/*
|
||||
@@ -153,14 +154,14 @@ static int _devices_disp(struct report_handle *rh, struct field *field,
|
||||
}
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
switch (seg->area[s].type) {
|
||||
switch (seg_type(seg, s)) {
|
||||
case AREA_LV:
|
||||
name = seg->area[s].u.lv.lv->name;
|
||||
extent = seg->area[s].u.lv.le;
|
||||
name = seg_lv(seg, s)->name;
|
||||
extent = seg_le(seg, s);
|
||||
break;
|
||||
case AREA_PV:
|
||||
name = dev_name(seg->area[s].u.pv.pv->dev);
|
||||
extent = seg->area[s].u.pv.pe;
|
||||
name = dev_name(seg_dev(seg, s));
|
||||
extent = seg_pe(seg, s);
|
||||
break;
|
||||
default:
|
||||
name = "unknown";
|
||||
@@ -324,7 +325,7 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field,
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct lvinfo info;
|
||||
char *repstr;
|
||||
struct snapshot *snap;
|
||||
struct lv_segment *snap_seg;
|
||||
float snap_percent;
|
||||
|
||||
if (!(repstr = pool_zalloc(rh->mem, 7))) {
|
||||
@@ -336,6 +337,10 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field,
|
||||
repstr[0] = 'p';
|
||||
else if (lv->status & MIRRORED)
|
||||
repstr[0] = 'm';
|
||||
else if (lv->status & MIRROR_IMAGE)
|
||||
repstr[0] = 'i';
|
||||
else if (lv->status & MIRROR_LOG)
|
||||
repstr[0] = 'l';
|
||||
else if (lv->status & VIRTUAL)
|
||||
repstr[0] = 'v';
|
||||
else if (lv_is_origin(lv))
|
||||
@@ -373,8 +378,8 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field,
|
||||
repstr[5] = '-';
|
||||
|
||||
/* Snapshot dropped? */
|
||||
if ((snap = find_cow(lv)) &&
|
||||
(!lv_snapshot_percent(snap->cow, &snap_percent) ||
|
||||
if ((snap_seg = find_cow(lv)) &&
|
||||
(!lv_snapshot_percent(snap_seg->cow, &snap_percent) ||
|
||||
snap_percent < 0 || snap_percent >= 100)) {
|
||||
repstr[0] = toupper(repstr[0]);
|
||||
if (info.suspended)
|
||||
@@ -478,10 +483,10 @@ static int _origin_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct snapshot *snap;
|
||||
struct lv_segment *snap_seg;
|
||||
|
||||
if ((snap = find_cow(lv)))
|
||||
return _string_disp(rh, field, &snap->origin->name);
|
||||
if ((snap_seg = find_cow(lv)))
|
||||
return _string_disp(rh, field, &snap_seg->origin->name);
|
||||
|
||||
field->report_string = "";
|
||||
field->sort_value = (const void *) field->report_string;
|
||||
@@ -489,19 +494,68 @@ static int _origin_disp(struct report_handle *rh, struct field *field,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _loglv_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct lv_segment *seg;
|
||||
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (!seg_is_mirrored(seg) || !seg->log_lv)
|
||||
continue;
|
||||
return _string_disp(rh, field, &seg->log_lv->name);
|
||||
}
|
||||
|
||||
field->report_string = "";
|
||||
field->sort_value = (const void *) field->report_string;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvname_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
char *repstr;
|
||||
size_t len;
|
||||
|
||||
if (lv->status & VISIBLE_LV) {
|
||||
repstr = lv->name;
|
||||
return _string_disp(rh, field, &repstr);
|
||||
}
|
||||
|
||||
len = strlen(lv->name) + 3;
|
||||
if (!(repstr = pool_zalloc(rh->mem, len))) {
|
||||
log_error("pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(repstr, len, "[%s]", lv->name) < 0) {
|
||||
log_error("lvname snprintf failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
field->report_string = repstr;
|
||||
|
||||
if (!(field->sort_value = pool_strdup(rh->mem, lv->name))) {
|
||||
log_error("pool_strdup failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _movepv_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const char *name;
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (!(seg->status & PVMOVE))
|
||||
continue;
|
||||
name = dev_name(seg->area[0].u.pv.pv->dev);
|
||||
name = dev_name(seg_dev(seg, 0));
|
||||
return _string_disp(rh, field, &name);
|
||||
}
|
||||
|
||||
@@ -573,7 +627,7 @@ static int _vgsize_disp(struct report_handle *rh, struct field *field,
|
||||
const struct volume_group *vg = (const struct volume_group *) data;
|
||||
uint64_t size;
|
||||
|
||||
size = vg->extent_count * vg->extent_size;
|
||||
size = (uint64_t) vg->extent_count * vg->extent_size;
|
||||
|
||||
return _size64_disp(rh, field, &size);
|
||||
}
|
||||
@@ -584,7 +638,7 @@ static int _segstart_disp(struct report_handle *rh, struct field *field,
|
||||
const struct lv_segment *seg = (const struct lv_segment *) data;
|
||||
uint64_t start;
|
||||
|
||||
start = seg->le * seg->lv->vg->extent_size;
|
||||
start = (uint64_t) seg->le * seg->lv->vg->extent_size;
|
||||
|
||||
return _size64_disp(rh, field, &start);
|
||||
}
|
||||
@@ -595,7 +649,7 @@ static int _segsize_disp(struct report_handle *rh, struct field *field,
|
||||
const struct lv_segment *seg = (const struct lv_segment *) data;
|
||||
uint64_t size;
|
||||
|
||||
size = seg->len * seg->lv->vg->extent_size;
|
||||
size = (uint64_t) seg->len * seg->lv->vg->extent_size;
|
||||
|
||||
return _size64_disp(rh, field, &size);
|
||||
}
|
||||
@@ -610,7 +664,7 @@ static int _pvused_disp(struct report_handle *rh, struct field *field,
|
||||
if (!pv->pe_count)
|
||||
used = 0LL;
|
||||
else
|
||||
used = pv->pe_alloc_count * pv->pe_size;
|
||||
used = (uint64_t) pv->pe_alloc_count * pv->pe_size;
|
||||
|
||||
return _size64_disp(rh, field, &used);
|
||||
}
|
||||
@@ -625,7 +679,7 @@ static int _pvfree_disp(struct report_handle *rh, struct field *field,
|
||||
if (!pv->pe_count)
|
||||
freespace = pv->size;
|
||||
else
|
||||
freespace = (pv->pe_count - pv->pe_alloc_count) * pv->pe_size;
|
||||
freespace = (uint64_t) (pv->pe_count - pv->pe_alloc_count) * pv->pe_size;
|
||||
|
||||
return _size64_disp(rh, field, &freespace);
|
||||
}
|
||||
@@ -640,7 +694,7 @@ static int _pvsize_disp(struct report_handle *rh, struct field *field,
|
||||
if (!pv->pe_count)
|
||||
size = pv->size;
|
||||
else
|
||||
size = pv->pe_count * pv->pe_size;
|
||||
size = (uint64_t) pv->pe_count * pv->pe_size;
|
||||
|
||||
return _size64_disp(rh, field, &size);
|
||||
}
|
||||
@@ -663,7 +717,7 @@ static int _vgfree_disp(struct report_handle *rh, struct field *field,
|
||||
const struct volume_group *vg = (const struct volume_group *) data;
|
||||
uint64_t freespace;
|
||||
|
||||
freespace = vg->free_count * vg->extent_size;
|
||||
freespace = (uint64_t) vg->free_count * vg->extent_size;
|
||||
|
||||
return _size64_disp(rh, field, &freespace);
|
||||
}
|
||||
@@ -762,7 +816,7 @@ static int _snpercent_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct snapshot *snap;
|
||||
struct lv_segment *snap_seg;
|
||||
struct lvinfo info;
|
||||
float snap_percent;
|
||||
uint64_t *sortval;
|
||||
@@ -773,15 +827,16 @@ static int _snpercent_disp(struct report_handle *rh, struct field *field,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(snap = find_cow(lv)) ||
|
||||
(lv_info(snap->cow, &info, 0) && !info.exists)) {
|
||||
if (!(snap_seg = find_cow(lv)) ||
|
||||
(lv_info(snap_seg->cow, &info, 0) && !info.exists)) {
|
||||
field->report_string = "";
|
||||
*sortval = UINT64_C(0);
|
||||
field->sort_value = sortval;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!lv_snapshot_percent(snap->cow, &snap_percent) || snap_percent < 0) {
|
||||
if (!lv_snapshot_percent(snap_seg->cow, &snap_percent)
|
||||
|| snap_percent < 0) {
|
||||
field->report_string = "100.00";
|
||||
*sortval = UINT64_C(100);
|
||||
field->sort_value = sortval;
|
||||
@@ -855,9 +910,9 @@ static int _copypercent_disp(struct report_handle *rh, struct field *field,
|
||||
|
||||
static struct {
|
||||
report_type_t type;
|
||||
const char id[30];
|
||||
const char id[32];
|
||||
off_t offset;
|
||||
const char heading[30];
|
||||
const char heading[32];
|
||||
int width;
|
||||
uint32_t flags;
|
||||
field_report_fn report_fn;
|
||||
@@ -915,12 +970,9 @@ static int _field_match(struct report_handle *rh, const char *field, size_t len)
|
||||
static int _add_sort_key(struct report_handle *rh, uint32_t field_num,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct list *fh;
|
||||
struct field_properties *fp, *found = NULL;
|
||||
|
||||
list_iterate(fh, &rh->field_props) {
|
||||
fp = list_item(fh, struct field_properties);
|
||||
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
if (fp->field_num == field_num) {
|
||||
found = fp;
|
||||
break;
|
||||
@@ -1077,6 +1129,9 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
|
||||
case SEGS:
|
||||
rh->field_prefix = "seg_";
|
||||
break;
|
||||
case PVSEGS:
|
||||
rh->field_prefix = "pvseg_";
|
||||
break;
|
||||
default:
|
||||
rh->field_prefix = "";
|
||||
}
|
||||
@@ -1096,6 +1151,8 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
|
||||
/* Ensure options selected are compatible */
|
||||
if (rh->type & SEGS)
|
||||
rh->type |= LVS;
|
||||
if (rh->type & PVSEGS)
|
||||
rh->type |= PVS;
|
||||
if ((rh->type & LVS) && (rh->type & PVS)) {
|
||||
log_error("Can't report LV and PV fields at the same time");
|
||||
return NULL;
|
||||
@@ -1106,6 +1163,8 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
|
||||
*report_type = SEGS;
|
||||
else if (rh->type & LVS)
|
||||
*report_type = LVS;
|
||||
else if (rh->type & PVSEGS)
|
||||
*report_type = PVSEGS;
|
||||
else if (rh->type & PVS)
|
||||
*report_type = PVS;
|
||||
|
||||
@@ -1126,10 +1185,9 @@ void report_free(void *handle)
|
||||
*/
|
||||
int report_object(void *handle, struct volume_group *vg,
|
||||
struct logical_volume *lv, struct physical_volume *pv,
|
||||
struct lv_segment *seg)
|
||||
struct lv_segment *seg, struct pv_segment *pvseg)
|
||||
{
|
||||
struct report_handle *rh = handle;
|
||||
struct list *fh;
|
||||
struct field_properties *fp;
|
||||
struct row *row;
|
||||
struct field *field;
|
||||
@@ -1159,9 +1217,7 @@ int report_object(void *handle, struct volume_group *vg,
|
||||
list_add(&rh->rows, &row->list);
|
||||
|
||||
/* For each field to be displayed, call its report_fn */
|
||||
list_iterate(fh, &rh->field_props) {
|
||||
fp = list_item(fh, struct field_properties);
|
||||
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
skip = 0;
|
||||
|
||||
if (!(field = pool_zalloc(rh->mem, sizeof(*field)))) {
|
||||
@@ -1186,6 +1242,9 @@ int report_object(void *handle, struct volume_group *vg,
|
||||
break;
|
||||
case SEGS:
|
||||
data = (void *) seg + _fields[fp->field_num].offset;
|
||||
break;
|
||||
case PVSEGS:
|
||||
data = (void *) pvseg + _fields[fp->field_num].offset;
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
@@ -1219,7 +1278,6 @@ int report_object(void *handle, struct volume_group *vg,
|
||||
static int _report_headings(void *handle)
|
||||
{
|
||||
struct report_handle *rh = handle;
|
||||
struct list *fh;
|
||||
struct field_properties *fp;
|
||||
const char *heading;
|
||||
char buf[1024];
|
||||
@@ -1238,8 +1296,7 @@ static int _report_headings(void *handle)
|
||||
}
|
||||
|
||||
/* First heading line */
|
||||
list_iterate(fh, &rh->field_props) {
|
||||
fp = list_item(fh, struct field_properties);
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
if (fp->flags & FLD_HIDDEN)
|
||||
continue;
|
||||
|
||||
@@ -1256,7 +1313,7 @@ static int _report_headings(void *handle)
|
||||
} else if (!pool_grow_object(rh->mem, heading, strlen(heading)))
|
||||
goto bad;
|
||||
|
||||
if (!list_end(&rh->field_props, fh))
|
||||
if (!list_end(&rh->field_props, &fp->list))
|
||||
if (!pool_grow_object(rh->mem, rh->separator,
|
||||
strlen(rh->separator)))
|
||||
goto bad;
|
||||
@@ -1324,7 +1381,6 @@ static int _row_compare(const void *a, const void *b)
|
||||
static int _sort_rows(struct report_handle *rh)
|
||||
{
|
||||
struct row *(*rows)[];
|
||||
struct list *rowh;
|
||||
uint32_t count = 0;
|
||||
struct row *row;
|
||||
|
||||
@@ -1334,10 +1390,8 @@ static int _sort_rows(struct report_handle *rh)
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(rowh, &rh->rows) {
|
||||
row = list_item(rowh, struct row);
|
||||
list_iterate_items(row, &rh->rows)
|
||||
(*rows)[count++] = row;
|
||||
}
|
||||
|
||||
qsort(rows, count, sizeof(**rows), _row_compare);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#include "metadata.h"
|
||||
|
||||
typedef enum { LVS = 1, PVS = 2, VGS = 4, SEGS = 8 } report_type_t;
|
||||
typedef enum { LVS = 1, PVS = 2, VGS = 4, SEGS = 8, PVSEGS = 16 } report_type_t;
|
||||
|
||||
struct field;
|
||||
struct report_handle;
|
||||
@@ -32,7 +32,7 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
|
||||
void report_free(void *handle);
|
||||
int report_object(void *handle, struct volume_group *vg,
|
||||
struct logical_volume *lv, struct physical_volume *pv,
|
||||
struct lv_segment *seg);
|
||||
struct lv_segment *seg, struct pv_segment *pvseg);
|
||||
int report_output(void *handle);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -70,7 +70,8 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg_add_snapshot(org, cow, 1, &seg->lv->lvid.id[1], chunk_size)) {
|
||||
if (!vg_add_snapshot(seg->lv->vg->fid, seg->lv->name, org, cow,
|
||||
&seg->lv->lvid, seg->len, chunk_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "targets.h"
|
||||
#include "lvm-string.h"
|
||||
#include "activate.h"
|
||||
#include "pv_alloc.h"
|
||||
|
||||
static const char *_name(const struct lv_segment *seg)
|
||||
{
|
||||
@@ -81,7 +82,7 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn,
|
||||
|
||||
seg->area_len /= seg->area_count;
|
||||
|
||||
return text_import_areas(seg, sn, cn, pv_hash);
|
||||
return text_import_areas(seg, sn, cn, pv_hash, 0);
|
||||
}
|
||||
|
||||
static int _text_export(const struct lv_segment *seg, struct formatter *f)
|
||||
@@ -118,8 +119,10 @@ static int _segments_compatible(struct lv_segment *first,
|
||||
|
||||
width = first->area_len;
|
||||
|
||||
if ((first->area[s].u.pv.pv != second->area[s].u.pv.pv) ||
|
||||
(first->area[s].u.pv.pe + width != second->area[s].u.pv.pe))
|
||||
if ((seg_pv(first, s) !=
|
||||
seg_pv(second, s)) ||
|
||||
(seg_pe(first, s) + width !=
|
||||
seg_pe(second, s)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -131,12 +134,19 @@ static int _segments_compatible(struct lv_segment *first,
|
||||
|
||||
static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
|
||||
{
|
||||
uint32_t s;
|
||||
|
||||
if (!_segments_compatible(seg1, seg2))
|
||||
return 0;
|
||||
|
||||
seg1->len += seg2->len;
|
||||
seg1->area_len += seg2->area_len;
|
||||
|
||||
for (s = 0; s < seg1->area_count; s++)
|
||||
if (seg1->area[s].type == AREA_PV)
|
||||
merge_pv_segments(seg_pvseg(seg1, s),
|
||||
seg_pvseg(seg2, s));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user