mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-11-03 08:23:48 +03:00 
			
		
		
		
	Compare commits
	
		
			113 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					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 | ||
| 
						 | 
					fe3a37f89d | ||
| 
						 | 
					8aea44e77b | ||
| 
						 | 
					5529aec0d6 | ||
| 
						 | 
					369549d23f | 
							
								
								
									
										101
									
								
								WHATS_NEW
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								WHATS_NEW
									
									
									
									
									
								
							@@ -1,6 +1,103 @@
 | 
			
		||||
Version 2.00.34 - 
 | 
			
		||||
==================================
 | 
			
		||||
Version 2.01.10 - 
 | 
			
		||||
================================
 | 
			
		||||
  Tidy lv_segment interface.
 | 
			
		||||
  Initial 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.
 | 
			
		||||
  Enable building of CMAN & GULM versions of clvmd into a single binary
 | 
			
		||||
 | 
			
		||||
Version 2.00.33 - 7th January 2005
 | 
			
		||||
==================================
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								WHATS_NEW_DM
									
									
									
									
									
								
							@@ -1,5 +1,15 @@
 | 
			
		||||
Version 1.01.00 -
 | 
			
		||||
============================
 | 
			
		||||
Version 1.01.02 - 
 | 
			
		||||
=============================
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
Version 1.00.21 - 7 Jan 2005
 | 
			
		||||
 
 | 
			
		||||
@@ -281,12 +281,12 @@ AC_MSG_RESULT($SELINUX)
 | 
			
		||||
dnl -- Build cluster LVM daemon
 | 
			
		||||
AC_MSG_CHECKING(whether to build cluster LVM daemon)
 | 
			
		||||
AC_ARG_WITH(clvmd,
 | 
			
		||||
  [  --with-clvmd=TYPE       Build cluster LVM Daemon: cman/gulm/none
 | 
			
		||||
  [  --with-clvmd=TYPE       Build cluster LVM Daemon: cman/gulm/none/all
 | 
			
		||||
                          [TYPE=none] ],
 | 
			
		||||
  [ CLVMD="$withval" ],
 | 
			
		||||
  [ CLVMD="none" ])
 | 
			
		||||
if test x$CLVMD = xyes; then
 | 
			
		||||
	CLVMD=cman
 | 
			
		||||
	CLVMD=all
 | 
			
		||||
fi
 | 
			
		||||
AC_MSG_RESULT($CLVMD)
 | 
			
		||||
 | 
			
		||||
@@ -481,7 +481,7 @@ if test x$READLINE = xyes; then
 | 
			
		||||
	AC_CHECK_HEADERS(readline/readline.h readline/history.h,,AC_MSG_ERROR(bailing out))
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if test x$CLVMD = xyes; then
 | 
			
		||||
if test x$CLVMD != xnone; then
 | 
			
		||||
	AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out))
 | 
			
		||||
	AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,AC_MSG_ERROR(bailing out))
 | 
			
		||||
	AC_FUNC_GETMNTENT
 | 
			
		||||
 
 | 
			
		||||
@@ -18,19 +18,36 @@ VPATH = @srcdir@
 | 
			
		||||
SOURCES = \
 | 
			
		||||
	clvmd-command.c  \
 | 
			
		||||
	clvmd.c          \
 | 
			
		||||
	libclvm.c        \
 | 
			
		||||
	lvm-functions.c  \
 | 
			
		||||
	system-lv.c
 | 
			
		||||
 | 
			
		||||
ifeq ("@CLVMD@", "gulm")
 | 
			
		||||
	GULM = yes
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@CLVMD@", "cman")
 | 
			
		||||
	CMAN = yes
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@CLVMD@", "all")
 | 
			
		||||
	GULM = yes
 | 
			
		||||
	CMAN = yes
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@DEBUG@", "yes")
 | 
			
		||||
	CFLAGS += -DDEBUG
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("$(GULM)", "yes")
 | 
			
		||||
	SOURCES += clvmd-gulm.c tcp-comms.c
 | 
			
		||||
	LMLIBS += -lccs -lgulm
 | 
			
		||||
	CFLAGS += -DUSE_GULM
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ("@CLVMD@", "cman")
 | 
			
		||||
ifeq ("$(CMAN)", "yes")
 | 
			
		||||
	SOURCES += clvmd-cman.c
 | 
			
		||||
	LMLIBS += -ldlm
 | 
			
		||||
	CFLAGS += -DUSE_CMAN
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
TARGETS = \
 | 
			
		||||
 
 | 
			
		||||
@@ -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";
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,7 @@ struct lock_wait {
 | 
			
		||||
	struct dlm_lksb lksb;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int init_cluster()
 | 
			
		||||
static int _init_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	struct sockaddr_cl saddr;
 | 
			
		||||
	int port = CLUSTER_PORT_CLVMD;
 | 
			
		||||
@@ -74,9 +74,11 @@ int init_cluster()
 | 
			
		||||
	/* Open the cluster communication socket */
 | 
			
		||||
	cluster_sock = socket(AF_CLUSTER, SOCK_DGRAM, CLPROTO_CLIENT);
 | 
			
		||||
	if (cluster_sock == -1) {
 | 
			
		||||
		syslog(LOG_ERR, "Can't open 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,21 +103,27 @@ int init_cluster()
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	dlm_ls_pthread_init(lockspace);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_main_cluster_fd()
 | 
			
		||||
static void _cluster_init_completed(void)
 | 
			
		||||
{
 | 
			
		||||
	clvmd_cluster_init_completed();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_main_cluster_fd()
 | 
			
		||||
{
 | 
			
		||||
	return cluster_sock;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_num_nodes()
 | 
			
		||||
static int _get_num_nodes()
 | 
			
		||||
{
 | 
			
		||||
	return num_nodes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* send_message with the fd check removed */
 | 
			
		||||
int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
 | 
			
		||||
static int _cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
 | 
			
		||||
{
 | 
			
		||||
	struct iovec iov[2];
 | 
			
		||||
	struct msghdr msg;
 | 
			
		||||
@@ -135,7 +143,7 @@ int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
 | 
			
		||||
	if (csid) {
 | 
			
		||||
		msg.msg_name = &saddr;
 | 
			
		||||
		msg.msg_namelen = sizeof(saddr);
 | 
			
		||||
		memcpy(&saddr.scl_nodeid, csid, MAX_CSID_LEN);
 | 
			
		||||
		memcpy(&saddr.scl_nodeid, csid, CMAN_MAX_CSID_LEN);
 | 
			
		||||
	} else {		/* Cluster broadcast */
 | 
			
		||||
 | 
			
		||||
		msg.msg_name = NULL;
 | 
			
		||||
@@ -151,26 +159,26 @@ int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void get_our_csid(char *csid)
 | 
			
		||||
static void _get_our_csid(char *csid)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	memset(csid, 0, MAX_CSID_LEN);
 | 
			
		||||
	memset(csid, 0, CMAN_MAX_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_nodes; i++) {
 | 
			
		||||
		if (nodes[i].us)
 | 
			
		||||
			memcpy(csid, &nodes[i].node_id, MAX_CSID_LEN);
 | 
			
		||||
			memcpy(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Call a callback routine for each node that known (down mean not running a clvmd) */
 | 
			
		||||
int cluster_do_node_callback(struct local_client *client,
 | 
			
		||||
static int _cluster_do_node_callback(struct local_client *client,
 | 
			
		||||
			     void (*callback) (struct local_client *, char *,
 | 
			
		||||
					       int))
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	int somedown = 0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < get_num_nodes(); i++) {
 | 
			
		||||
	for (i = 0; i < _get_num_nodes(); i++) {
 | 
			
		||||
		callback(client, (char *)&nodes[i].node_id, node_updown[nodes[i].node_id]);
 | 
			
		||||
		if (!node_updown[nodes[i].node_id])
 | 
			
		||||
			somedown = -1;
 | 
			
		||||
@@ -202,7 +210,7 @@ static void process_oob_msg(char *buf, int len, int nodeid)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cluster_fd_callback(struct local_client *client, char *buf, int len, char *csid,
 | 
			
		||||
static int _cluster_fd_callback(struct local_client *client, char *buf, int len, char *csid,
 | 
			
		||||
			struct local_client **new_client)
 | 
			
		||||
{
 | 
			
		||||
	struct iovec iov[2];
 | 
			
		||||
@@ -254,7 +262,7 @@ int cluster_fd_callback(struct local_client *client, char *buf, int len, char *c
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void add_up_node(char *csid)
 | 
			
		||||
static void _add_up_node(char *csid)
 | 
			
		||||
{
 | 
			
		||||
	/* It's up ! */
 | 
			
		||||
	int nodeid = nodeid_from_csid(csid);
 | 
			
		||||
@@ -278,7 +286,7 @@ void add_up_node(char *csid)
 | 
			
		||||
	DEBUGLOG("Added new node %d to updown list\n", nodeid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cluster_closedown()
 | 
			
		||||
static void _cluster_closedown()
 | 
			
		||||
{
 | 
			
		||||
	unlock_all();
 | 
			
		||||
	dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
 | 
			
		||||
@@ -307,7 +315,7 @@ static int is_listening(int nodeid)
 | 
			
		||||
 | 
			
		||||
/* Populate the list of CLVMDs running.
 | 
			
		||||
   called only at startup time */
 | 
			
		||||
void count_clvmds_running(void)
 | 
			
		||||
static void count_clvmds_running(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
@@ -366,13 +374,13 @@ static void get_members()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Convert a node name to a CSID */
 | 
			
		||||
int csid_from_name(char *csid, char *name)
 | 
			
		||||
static int _csid_from_name(char *csid, char *name)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_nodes; i++) {
 | 
			
		||||
		if (strcmp(name, nodes[i].name) == 0) {
 | 
			
		||||
			memcpy(csid, &nodes[i].node_id, MAX_CSID_LEN);
 | 
			
		||||
			memcpy(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -380,12 +388,12 @@ int csid_from_name(char *csid, char *name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Convert a CSID to a node name */
 | 
			
		||||
int name_from_csid(char *csid, char *name)
 | 
			
		||||
static int _name_from_csid(char *csid, char *name)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_nodes; i++) {
 | 
			
		||||
		if (memcmp(csid, &nodes[i].node_id, MAX_CSID_LEN) == 0) {
 | 
			
		||||
		if (memcmp(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN) == 0) {
 | 
			
		||||
			strcpy(name, nodes[i].name);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
@@ -396,7 +404,7 @@ int name_from_csid(char *csid, char *name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Convert a node ID to a node name */
 | 
			
		||||
int name_from_nodeid(int nodeid, char *name)
 | 
			
		||||
static int name_from_nodeid(int nodeid, char *name)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
@@ -416,12 +424,12 @@ static int nodeid_from_csid(char *csid)
 | 
			
		||||
{
 | 
			
		||||
        int nodeid;
 | 
			
		||||
 | 
			
		||||
	memcpy(&nodeid, csid, MAX_CSID_LEN);
 | 
			
		||||
	memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
	return nodeid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int is_quorate()
 | 
			
		||||
static int _is_quorate()
 | 
			
		||||
{
 | 
			
		||||
	return ioctl(cluster_sock, SIOCCLUSTER_ISQUORATE, 0);
 | 
			
		||||
}
 | 
			
		||||
@@ -435,7 +443,7 @@ static void sync_ast_routine(void *arg)
 | 
			
		||||
	pthread_mutex_unlock(&lwait->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int sync_lock(const char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	struct lock_wait lwait;
 | 
			
		||||
@@ -478,7 +486,7 @@ int sync_lock(const char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int sync_unlock(const char *resource /* UNUSED */, int lockid)
 | 
			
		||||
static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	struct lock_wait lwait;
 | 
			
		||||
@@ -505,3 +513,28 @@ int sync_unlock(const char *resource /* UNUSED */, int lockid)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct cluster_ops _cluster_cman_ops = {
 | 
			
		||||
	.cluster_init_completed   = _cluster_init_completed,
 | 
			
		||||
	.cluster_send_message     = _cluster_send_message,
 | 
			
		||||
	.name_from_csid           = _name_from_csid,
 | 
			
		||||
	.csid_from_name           = _csid_from_name,
 | 
			
		||||
	.get_num_nodes            = _get_num_nodes,
 | 
			
		||||
	.cluster_fd_callback      = _cluster_fd_callback,
 | 
			
		||||
	.get_main_cluster_fd      = _get_main_cluster_fd,
 | 
			
		||||
	.cluster_do_node_callback = _cluster_do_node_callback,
 | 
			
		||||
	.is_quorate               = _is_quorate,
 | 
			
		||||
	.get_our_csid             = _get_our_csid,
 | 
			
		||||
	.add_up_node              = _add_up_node,
 | 
			
		||||
	.cluster_closedown        = _cluster_closedown,
 | 
			
		||||
	.sync_lock                = _sync_lock,
 | 
			
		||||
	.sync_unlock              = _sync_unlock,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct cluster_ops *init_cman_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!_init_cluster())
 | 
			
		||||
		return &_cluster_cman_ops;
 | 
			
		||||
	else
 | 
			
		||||
		return NULL;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -22,33 +22,48 @@
 | 
			
		||||
 | 
			
		||||
struct local_client;
 | 
			
		||||
 | 
			
		||||
extern int cluster_send_message(void *buf, int msglen, char *csid,
 | 
			
		||||
struct cluster_ops {
 | 
			
		||||
	void (*cluster_init_completed) (void);
 | 
			
		||||
 | 
			
		||||
	int (*cluster_send_message) (void *buf, int msglen, char *csid,
 | 
			
		||||
				const char *errtext);
 | 
			
		||||
extern int name_from_csid(char *csid, char *name);
 | 
			
		||||
extern int csid_from_name(char *csid, char *name);
 | 
			
		||||
extern int get_num_nodes(void);
 | 
			
		||||
extern int cluster_fd_callback(struct local_client *fd, char *buf, int len,
 | 
			
		||||
	int (*name_from_csid) (char *csid, char *name);
 | 
			
		||||
	int (*csid_from_name) (char *csid, char *name);
 | 
			
		||||
	int (*get_num_nodes) (void);
 | 
			
		||||
	int (*cluster_fd_callback) (struct local_client *fd, char *buf, int len,
 | 
			
		||||
			       char *csid, struct local_client **new_client);
 | 
			
		||||
extern int init_cluster(void);
 | 
			
		||||
extern int get_main_cluster_fd(void);	/* gets accept FD or cman cluster socket */
 | 
			
		||||
extern int cluster_do_node_callback(struct local_client *client,
 | 
			
		||||
	int (*get_main_cluster_fd) (void);	/* gets accept FD or cman cluster socket */
 | 
			
		||||
	int (*cluster_do_node_callback) (struct local_client *client,
 | 
			
		||||
				    void (*callback) (struct local_client *,
 | 
			
		||||
						      char *csid, int node_up));
 | 
			
		||||
extern int is_quorate(void);
 | 
			
		||||
	int (*is_quorate) (void);
 | 
			
		||||
 | 
			
		||||
extern void get_our_csid(char *csid);
 | 
			
		||||
extern void add_up_node(char *csid);
 | 
			
		||||
extern void cluster_closedown(void);
 | 
			
		||||
	void (*get_our_csid) (char *csid);
 | 
			
		||||
	void (*add_up_node) (char *csid);
 | 
			
		||||
	void (*reread_config) (void);
 | 
			
		||||
	void (*cluster_closedown) (void);
 | 
			
		||||
 | 
			
		||||
extern int sync_lock(const char *resource, int mode, int flags, int *lockid);
 | 
			
		||||
extern int sync_unlock(const char *resource, int lockid);
 | 
			
		||||
	int (*sync_lock) (const char *resource, int mode, int flags, int *lockid);
 | 
			
		||||
	int (*sync_unlock) (const char *resource, int lockid);
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef USE_GULM
 | 
			
		||||
#  include "tcp-comms.h"
 | 
			
		||||
#else
 | 
			
		||||
/* cman */
 | 
			
		||||
struct cluster_ops *init_gulm_cluster(void);
 | 
			
		||||
#define MAX_CSID_LEN 			GULM_MAX_CSID_LEN
 | 
			
		||||
#define MAX_CLUSTER_MEMBER_NAME_LEN	GULM_MAX_CLUSTER_MEMBER_NAME_LEN
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_CMAN
 | 
			
		||||
#  include "cnxman-socket.h"
 | 
			
		||||
#define MAX_CSID_LEN 4
 | 
			
		||||
#  define CMAN_MAX_CSID_LEN 4
 | 
			
		||||
#  ifndef MAX_CSID_LEN
 | 
			
		||||
#    define MAX_CSID_LEN CMAN_MAX_CSID_LEN
 | 
			
		||||
#  endif
 | 
			
		||||
#  undef MAX_CLUSTER_MEMBER_NAME_LEN
 | 
			
		||||
#  define MAX_CLUSTER_MEMBER_NAME_LEN	CMAN_MAX_CLUSTER_MEMBER_NAME_LEN
 | 
			
		||||
struct cluster_ops *init_cman_cluster(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -72,7 +76,7 @@ static volatile int lock_start_flag;
 | 
			
		||||
struct node_info
 | 
			
		||||
{
 | 
			
		||||
    enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state;
 | 
			
		||||
    char name[MAX_CLUSTER_MEMBER_NAME_LEN];
 | 
			
		||||
    char name[GULM_MAX_CLUSTER_MEMBER_NAME_LEN];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct lock_wait
 | 
			
		||||
@@ -88,6 +92,8 @@ static int read_from_core_sock(struct local_client *client, char *buf, int len,
 | 
			
		||||
static int read_from_lock_sock(struct local_client *client, char *buf, int len, char *csid,
 | 
			
		||||
			       struct local_client **new_client);
 | 
			
		||||
static int get_all_cluster_nodes(void);
 | 
			
		||||
static int _csid_from_name(char *csid, char *name);
 | 
			
		||||
static void _cluster_closedown(void);
 | 
			
		||||
 | 
			
		||||
/* In tcp-comms.c */
 | 
			
		||||
extern struct hash_table *sock_hash;
 | 
			
		||||
@@ -112,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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -123,19 +132,18 @@ static lg_lockspace_callbacks_t lock_callbacks;
 | 
			
		||||
static void badsig_handler(int sig)
 | 
			
		||||
{
 | 
			
		||||
    DEBUGLOG("got sig %d\n", sig);
 | 
			
		||||
    cluster_closedown();
 | 
			
		||||
    _cluster_closedown();
 | 
			
		||||
    exit(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sighup_handler(int sig)
 | 
			
		||||
static void _reread_config(void)
 | 
			
		||||
{
 | 
			
		||||
    DEBUGLOG("got SIGHUP\n");
 | 
			
		||||
 | 
			
		||||
        /* Re-read CCS node list */
 | 
			
		||||
	DEBUGLOG("Re-reading CCS config\n");
 | 
			
		||||
	get_all_cluster_nodes();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int init_cluster()
 | 
			
		||||
static int _init_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
    int status;
 | 
			
		||||
    int ccs_h;
 | 
			
		||||
@@ -222,7 +230,7 @@ int init_cluster()
 | 
			
		||||
	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)
 | 
			
		||||
@@ -235,15 +243,14 @@ int init_cluster()
 | 
			
		||||
    signal(SIGINT, badsig_handler);
 | 
			
		||||
    signal(SIGTERM, badsig_handler);
 | 
			
		||||
 | 
			
		||||
    /* Re-read the node list on SIGHUP */
 | 
			
		||||
    signal(SIGHUP, sighup_handler);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cluster_closedown()
 | 
			
		||||
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);
 | 
			
		||||
@@ -256,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)
 | 
			
		||||
@@ -301,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 */
 | 
			
		||||
@@ -328,18 +340,24 @@ 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;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    /* 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, num_nodes=%d\n",
 | 
			
		||||
	     ninfo->name, ninfo->state, num_nodes);
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
{
 | 
			
		||||
    struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
    ninfo = hash_lookup_binary(node_hash, (char *)ip, MAX_CSID_LEN);
 | 
			
		||||
    ninfo = hash_lookup_binary(node_hash, (char *)ip, GULM_MAX_CSID_LEN);
 | 
			
		||||
    if (!ninfo)
 | 
			
		||||
    {
 | 
			
		||||
	/* If we can't find that node then re-read the config file in case it
 | 
			
		||||
@@ -348,7 +366,7 @@ static struct node_info *add_or_set_node(char *name, struct in6_addr *ip, uint8_
 | 
			
		||||
	get_all_cluster_nodes();
 | 
			
		||||
 | 
			
		||||
	/* Now try again */
 | 
			
		||||
	ninfo = hash_lookup_binary(node_hash, (char *)ip, MAX_CSID_LEN);
 | 
			
		||||
	ninfo = hash_lookup_binary(node_hash, (char *)ip, GULM_MAX_CSID_LEN);
 | 
			
		||||
	if (!ninfo)
 | 
			
		||||
	{
 | 
			
		||||
	    DEBUGLOG("Ignoring node %s, not part of the SAN cluster\n", name);
 | 
			
		||||
@@ -356,11 +374,16 @@ 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _get_our_csid(char *csid)
 | 
			
		||||
{
 | 
			
		||||
	get_our_gulm_csid(csid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int core_nodelist(void *misc, lglcb_t type, char *name, struct in6_addr *ip, uint8_t state)
 | 
			
		||||
{
 | 
			
		||||
    DEBUGLOG("CORE nodelist\n");
 | 
			
		||||
@@ -381,14 +404,23 @@ static int core_nodelist(void *misc, lglcb_t type, char *name, struct in6_addr *
 | 
			
		||||
	{
 | 
			
		||||
	    if (type == lglcb_stop)
 | 
			
		||||
	    {
 | 
			
		||||
		char ourcsid[MAX_CSID_LEN];
 | 
			
		||||
		char ourcsid[GULM_MAX_CSID_LEN];
 | 
			
		||||
 | 
			
		||||
		DEBUGLOG("Got Nodelist, stop\n");
 | 
			
		||||
		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);
 | 
			
		||||
		add_up_node(ourcsid);
 | 
			
		||||
		_get_our_csid(ourcsid);
 | 
			
		||||
		gulm_add_up_node(ourcsid);
 | 
			
		||||
	    }
 | 
			
		||||
	    else
 | 
			
		||||
	    {
 | 
			
		||||
@@ -402,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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -417,7 +454,7 @@ static int core_nodechange(void *misc, char *nodename, struct in6_addr *nodeip,
 | 
			
		||||
 | 
			
		||||
    /* If we don't get nodeip here, try a lookup by name */
 | 
			
		||||
    if (!nodeip)
 | 
			
		||||
	csid_from_name((char *)nodeip, nodename);
 | 
			
		||||
	_csid_from_name((char *)nodeip, nodename);
 | 
			
		||||
    if (!nodeip)
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
@@ -471,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)
 | 
			
		||||
    {
 | 
			
		||||
@@ -540,15 +581,15 @@ int get_next_node_csid(void **context, char *csid)
 | 
			
		||||
	return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    memcpy(csid, hash_get_key(node_hash, *context), MAX_CSID_LEN);
 | 
			
		||||
    memcpy(csid, hash_get_key(node_hash, *context), GULM_MAX_CSID_LEN);
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int name_from_csid(char *csid, char *name)
 | 
			
		||||
int gulm_name_from_csid(char *csid, char *name)
 | 
			
		||||
{
 | 
			
		||||
    struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
    ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
 | 
			
		||||
    ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
 | 
			
		||||
    if (!ninfo)
 | 
			
		||||
    {
 | 
			
		||||
        sprintf(name, "UNKNOWN %s", print_csid(csid));
 | 
			
		||||
@@ -560,7 +601,7 @@ int name_from_csid(char *csid, char *name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int csid_from_name(char *csid, char *name)
 | 
			
		||||
static int _csid_from_name(char *csid, char *name)
 | 
			
		||||
{
 | 
			
		||||
    struct hash_node *hn;
 | 
			
		||||
    struct node_info *ninfo;
 | 
			
		||||
@@ -570,29 +611,36 @@ int csid_from_name(char *csid, char *name)
 | 
			
		||||
	ninfo = hash_get_data(node_hash, hn);
 | 
			
		||||
	if (strcmp(ninfo->name, name) == 0)
 | 
			
		||||
	{
 | 
			
		||||
	    memcpy(csid, hash_get_key(node_hash, hn), MAX_CSID_LEN);
 | 
			
		||||
	    memcpy(csid, hash_get_key(node_hash, hn), GULM_MAX_CSID_LEN);
 | 
			
		||||
	    return 0;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_num_nodes()
 | 
			
		||||
static int _get_num_nodes()
 | 
			
		||||
{
 | 
			
		||||
    DEBUGLOG("num_nodes = %d\n", num_nodes);
 | 
			
		||||
    return num_nodes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Node is now known to be running a clvmd */
 | 
			
		||||
void add_up_node(char *csid)
 | 
			
		||||
void gulm_add_up_node(char *csid)
 | 
			
		||||
{
 | 
			
		||||
    struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
    ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
 | 
			
		||||
    if (!ninfo)
 | 
			
		||||
    ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -601,7 +649,7 @@ void add_down_node(char *csid)
 | 
			
		||||
{
 | 
			
		||||
    struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
    ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
 | 
			
		||||
    ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
 | 
			
		||||
    if (!ninfo)
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
@@ -609,12 +657,13 @@ 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 */
 | 
			
		||||
int cluster_do_node_callback(struct local_client *master_client,
 | 
			
		||||
static int _cluster_do_node_callback(struct local_client *master_client,
 | 
			
		||||
				     void (*callback)(struct local_client *, char *csid, int node_up))
 | 
			
		||||
{
 | 
			
		||||
    struct hash_node *hn;
 | 
			
		||||
@@ -622,17 +671,28 @@ int cluster_do_node_callback(struct local_client *master_client,
 | 
			
		||||
 | 
			
		||||
    hash_iterate(hn, node_hash)
 | 
			
		||||
    {
 | 
			
		||||
	char csid[MAX_CSID_LEN];
 | 
			
		||||
	char csid[GULM_MAX_CSID_LEN];
 | 
			
		||||
	struct local_client *client;
 | 
			
		||||
 | 
			
		||||
	ninfo = hash_get_data(node_hash, hn);
 | 
			
		||||
	memcpy(csid, hash_get_key(node_hash, hn), MAX_CSID_LEN);
 | 
			
		||||
	memcpy(csid, hash_get_key(node_hash, hn), GULM_MAX_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("down_callback. node %s, state = %d\n", ninfo->name, ninfo->state);
 | 
			
		||||
 | 
			
		||||
	client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
 | 
			
		||||
	if (client)
 | 
			
		||||
	client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
@@ -643,12 +703,10 @@ static int gulm_to_errno(int gulm_ret)
 | 
			
		||||
    switch (gulm_ret)
 | 
			
		||||
    {
 | 
			
		||||
    case lg_err_TryFailed:
 | 
			
		||||
    case lg_err_AlreadyPend:
 | 
			
		||||
	    errno = EAGAIN;
 | 
			
		||||
	    break;
 | 
			
		||||
 | 
			
		||||
    case lg_err_AlreadyPend:
 | 
			
		||||
	errno = EBUSY;
 | 
			
		||||
 | 
			
		||||
	/* More?? */
 | 
			
		||||
    default:
 | 
			
		||||
	    errno = EINVAL;
 | 
			
		||||
@@ -722,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);
 | 
			
		||||
@@ -742,7 +805,7 @@ static int _unlock_resource(char *resource, int lockid)
 | 
			
		||||
   To aid unlocking, we store the lock mode in the lockid (as GULM
 | 
			
		||||
   doesn't use this).
 | 
			
		||||
*/
 | 
			
		||||
int sync_lock(const char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
{
 | 
			
		||||
    int status;
 | 
			
		||||
    char lock1[strlen(resource)+3];
 | 
			
		||||
@@ -758,7 +821,7 @@ 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)
 | 
			
		||||
        {
 | 
			
		||||
@@ -770,10 +833,16 @@ 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:
 | 
			
		||||
@@ -786,7 +855,7 @@ int sync_lock(const char *resource, int mode, int flags, int *lockid)
 | 
			
		||||
    return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int sync_unlock(const char *resource, int lockid)
 | 
			
		||||
static int _sync_unlock(const char *resource, int lockid)
 | 
			
		||||
{
 | 
			
		||||
    int status = 0;
 | 
			
		||||
    char lock1[strlen(resource)+3];
 | 
			
		||||
@@ -800,36 +869,16 @@ 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;
 | 
			
		||||
    if (!status)
 | 
			
		||||
	    status = _unlock_resource(lock2, lockid);
 | 
			
		||||
	break;
 | 
			
		||||
 | 
			
		||||
    case LCK_READ:
 | 
			
		||||
	status = _unlock_resource(lock1, lockid);
 | 
			
		||||
	break;
 | 
			
		||||
 | 
			
		||||
    case LCK_WRITE:
 | 
			
		||||
	status = _unlock_resource(lock2, lockid);
 | 
			
		||||
	break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
    return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int is_quorate()
 | 
			
		||||
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
 | 
			
		||||
@@ -854,7 +903,7 @@ static int get_all_cluster_nodes()
 | 
			
		||||
    for (i=1;;i++)
 | 
			
		||||
    {
 | 
			
		||||
	char nodekey[256];
 | 
			
		||||
	char nodeip[MAX_CSID_LEN];
 | 
			
		||||
	char nodeip[GULM_MAX_CSID_LEN];
 | 
			
		||||
	int  clvmflag = 1;
 | 
			
		||||
	char *clvmflagstr;
 | 
			
		||||
	char key[256];
 | 
			
		||||
@@ -877,7 +926,7 @@ static int get_all_cluster_nodes()
 | 
			
		||||
	    struct node_info *ninfo;
 | 
			
		||||
 | 
			
		||||
	    /* If it's not in the list, then add it */
 | 
			
		||||
	    ninfo = hash_lookup_binary(node_hash, nodeip, MAX_CSID_LEN);
 | 
			
		||||
	    ninfo = hash_lookup_binary(node_hash, nodeip, GULM_MAX_CSID_LEN);
 | 
			
		||||
	    if (!ninfo)
 | 
			
		||||
	    {
 | 
			
		||||
		ninfo = malloc(sizeof(struct node_info));
 | 
			
		||||
@@ -890,7 +939,7 @@ static int get_all_cluster_nodes()
 | 
			
		||||
		strcpy(ninfo->name, nodename);
 | 
			
		||||
 | 
			
		||||
		ninfo->state = NODE_DOWN;
 | 
			
		||||
		hash_insert_binary(node_hash, nodeip, MAX_CSID_LEN, ninfo);
 | 
			
		||||
		hash_insert_binary(node_hash, nodeip, GULM_MAX_CSID_LEN, ninfo);
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
@@ -906,3 +955,43 @@ static int get_all_cluster_nodes()
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_main_cluster_fd(void)
 | 
			
		||||
{
 | 
			
		||||
	return get_main_gulm_cluster_fd();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid, struct local_client **new_client)
 | 
			
		||||
{
 | 
			
		||||
	return cluster_fd_gulm_callback(fd, buf, len, csid, new_client);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
 | 
			
		||||
{
 | 
			
		||||
	return gulm_cluster_send_message(buf, msglen, csid, errtext);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct cluster_ops _cluster_gulm_ops = {
 | 
			
		||||
	.cluster_init_completed   = NULL,
 | 
			
		||||
	.cluster_send_message     = _cluster_send_message,
 | 
			
		||||
	.name_from_csid           = gulm_name_from_csid,
 | 
			
		||||
	.csid_from_name           = _csid_from_name,
 | 
			
		||||
	.get_num_nodes            = _get_num_nodes,
 | 
			
		||||
	.cluster_fd_callback      = _cluster_fd_callback,
 | 
			
		||||
	.get_main_cluster_fd      = _get_main_cluster_fd,
 | 
			
		||||
	.cluster_do_node_callback = _cluster_do_node_callback,
 | 
			
		||||
	.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,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct cluster_ops *init_gulm_cluster(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!_init_cluster())
 | 
			
		||||
		return &_cluster_gulm_ops;
 | 
			
		||||
	else
 | 
			
		||||
		return NULL;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,3 +7,6 @@ extern int gulm_fd(void);
 | 
			
		||||
extern int get_ip_address(char *node, char *addr);
 | 
			
		||||
extern void tcp_remove_client(char *csid);
 | 
			
		||||
extern int alloc_client(int fd, char *csid, struct local_client **new_client);
 | 
			
		||||
 | 
			
		||||
void gulm_add_up_node(char *csid);
 | 
			
		||||
int gulm_name_from_csid(char *csid, char *name);
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
@@ -55,9 +56,9 @@
 | 
			
		||||
 | 
			
		||||
/* The maximum size of a message that will fit into a packet. Anything bigger
 | 
			
		||||
   than this is sent via the system LV */
 | 
			
		||||
#define MAX_INLINE_MESSAGE (MAX_CLUSTER_MESSAGE-sizeof(struct clvm_header))
 | 
			
		||||
#define MAX_INLINE_MESSAGE (max_cluster_message-sizeof(struct clvm_header))
 | 
			
		||||
 | 
			
		||||
#define ISLOCAL_CSID(c) (memcmp(c, our_csid, MAX_CSID_LEN) == 0)
 | 
			
		||||
#define ISLOCAL_CSID(c) (memcmp(c, our_csid, max_csid_len) == 0)
 | 
			
		||||
 | 
			
		||||
/* Head of the fd list. Also contains
 | 
			
		||||
   the cluster_socket details */
 | 
			
		||||
@@ -65,7 +66,12 @@ static struct local_client local_client_head;
 | 
			
		||||
 | 
			
		||||
static unsigned short global_xid = 0;	/* Last transaction ID issued */
 | 
			
		||||
 | 
			
		||||
static struct cluster_ops *clops = NULL;
 | 
			
		||||
 | 
			
		||||
static char our_csid[MAX_CSID_LEN];
 | 
			
		||||
static unsigned max_csid_len;
 | 
			
		||||
static unsigned max_cluster_message;
 | 
			
		||||
static unsigned max_cluster_member_name_len;
 | 
			
		||||
 | 
			
		||||
/* Structure of items on the LVM thread list */
 | 
			
		||||
struct lvm_thread_cmd {
 | 
			
		||||
@@ -81,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 */
 | 
			
		||||
@@ -94,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);
 | 
			
		||||
@@ -159,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;
 | 
			
		||||
@@ -214,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 */
 | 
			
		||||
@@ -227,10 +239,30 @@ 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 */
 | 
			
		||||
	if (init_cluster()) {
 | 
			
		||||
#ifdef USE_CMAN
 | 
			
		||||
	if ((clops = init_cman_cluster())) {
 | 
			
		||||
		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
 | 
			
		||||
	if (!clops)
 | 
			
		||||
		if ((clops = init_gulm_cluster())) {
 | 
			
		||||
			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
 | 
			
		||||
 | 
			
		||||
	if (!clops) {
 | 
			
		||||
		DEBUGLOG("Can't initialise cluster interface\n");
 | 
			
		||||
		log_error("Can't initialise cluster interface\n");
 | 
			
		||||
		child_init_signal(DFAIL_CLUSTER_IF);
 | 
			
		||||
@@ -239,12 +271,12 @@ int main(int argc, char *argv[])
 | 
			
		||||
 | 
			
		||||
	/* Save our CSID */
 | 
			
		||||
	uname(&nodeinfo);
 | 
			
		||||
	get_our_csid(our_csid);
 | 
			
		||||
	clops->get_our_csid(our_csid);
 | 
			
		||||
 | 
			
		||||
	/* Initialise the FD list head */
 | 
			
		||||
	local_client_head.fd = get_main_cluster_fd();
 | 
			
		||||
	local_client_head.fd = clops->get_main_cluster_fd();
 | 
			
		||||
	local_client_head.type = CLUSTER_MAIN_SOCK;
 | 
			
		||||
	local_client_head.callback = cluster_fd_callback;
 | 
			
		||||
	local_client_head.callback = clops->cluster_fd_callback;
 | 
			
		||||
 | 
			
		||||
	/* Add the local socket to the list */
 | 
			
		||||
	newfd = malloc(sizeof(struct local_client));
 | 
			
		||||
@@ -252,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;
 | 
			
		||||
@@ -260,15 +293,14 @@ 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);
 | 
			
		||||
 | 
			
		||||
#ifndef USE_GULM
 | 
			
		||||
	/* Tell the rest of the cluster our version number */
 | 
			
		||||
	/* CMAN can do this immediately, gulm needs to wait until
 | 
			
		||||
	   the core initialisation has finished and the node list
 | 
			
		||||
	   has been gathered */
 | 
			
		||||
	send_version_message();
 | 
			
		||||
#endif
 | 
			
		||||
	if (clops->cluster_init_completed)
 | 
			
		||||
		clops->cluster_init_completed();
 | 
			
		||||
 | 
			
		||||
	DEBUGLOG("clvmd ready for work\n");
 | 
			
		||||
	child_init_signal(SUCCESS);
 | 
			
		||||
@@ -319,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;
 | 
			
		||||
@@ -417,9 +450,9 @@ static void timedout_callback(struct local_client *client, char *csid,
 | 
			
		||||
{
 | 
			
		||||
	if (node_up) {
 | 
			
		||||
		struct node_reply *reply;
 | 
			
		||||
		char nodename[MAX_CLUSTER_MEMBER_NAME_LEN];
 | 
			
		||||
		char nodename[max_cluster_member_name_len];
 | 
			
		||||
 | 
			
		||||
		name_from_csid(csid, nodename);
 | 
			
		||||
		clops->name_from_csid(csid, nodename);
 | 
			
		||||
		DEBUGLOG("PJC: checking for a reply from %s\n", nodename);
 | 
			
		||||
		pthread_mutex_lock(&client->bits.localsock.reply_mutex);
 | 
			
		||||
 | 
			
		||||
@@ -448,7 +481,7 @@ static void timedout_callback(struct local_client *client, char *csid,
 | 
			
		||||
static void request_timed_out(struct local_client *client)
 | 
			
		||||
{
 | 
			
		||||
	DEBUGLOG("Request timed-out. padding\n");
 | 
			
		||||
	cluster_do_node_callback(client, timedout_callback);
 | 
			
		||||
	clops->cluster_do_node_callback(client, timedout_callback);
 | 
			
		||||
 | 
			
		||||
	if (client->bits.localsock.num_replies !=
 | 
			
		||||
	    client->bits.localsock.expected_replies) {
 | 
			
		||||
@@ -473,7 +506,7 @@ static void main_loop(int local_sock, int cmd_timeout)
 | 
			
		||||
		int select_status;
 | 
			
		||||
		struct local_client *thisfd;
 | 
			
		||||
		struct timeval tv = { cmd_timeout, 0 };
 | 
			
		||||
		int quorate = is_quorate();
 | 
			
		||||
		int quorate = clops->is_quorate();
 | 
			
		||||
 | 
			
		||||
		/* Wait on the cluster FD and all local sockets/pipes */
 | 
			
		||||
		FD_ZERO(&in);
 | 
			
		||||
@@ -485,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];
 | 
			
		||||
			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;
 | 
			
		||||
@@ -520,8 +578,9 @@ 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);
 | 
			
		||||
 | 
			
		||||
						/* Queue cleanup, this also frees the client struct */
 | 
			
		||||
						add_to_lvmqueue(free_fd, NULL, 0, NULL);
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
@@ -573,7 +632,7 @@ static void main_loop(int local_sock, int cmd_timeout)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      closedown:
 | 
			
		||||
	cluster_closedown();
 | 
			
		||||
	clops->cluster_closedown();
 | 
			
		||||
	close(local_sock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -696,7 +755,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);
 | 
			
		||||
@@ -765,7 +824,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,
 | 
			
		||||
@@ -788,7 +847,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,
 | 
			
		||||
@@ -829,13 +888,13 @@ static int read_from_local_sock(struct local_client *thisfd)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Check the node name for validity */
 | 
			
		||||
		if (inheader->node[0] && csid_from_name(csid, inheader->node)) {
 | 
			
		||||
		if (inheader->node[0] && clops->csid_from_name(csid, inheader->node)) {
 | 
			
		||||
			/* Error, node is not in the cluster */
 | 
			
		||||
			struct clvm_header reply;
 | 
			
		||||
			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,
 | 
			
		||||
@@ -866,7 +925,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,
 | 
			
		||||
@@ -877,6 +936,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;
 | 
			
		||||
@@ -961,7 +1021,7 @@ static int distribute_command(struct local_client *thisfd)
 | 
			
		||||
		/* if node is empty then do it on the whole cluster */
 | 
			
		||||
		if (inheader->node[0] == '\0') {
 | 
			
		||||
			thisfd->bits.localsock.expected_replies =
 | 
			
		||||
			    get_num_nodes();
 | 
			
		||||
			    clops->get_num_nodes();
 | 
			
		||||
			thisfd->bits.localsock.num_replies = 0;
 | 
			
		||||
			thisfd->bits.localsock.sent_time = time(NULL);
 | 
			
		||||
			thisfd->bits.localsock.in_progress = TRUE;
 | 
			
		||||
@@ -982,7 +1042,7 @@ static int distribute_command(struct local_client *thisfd)
 | 
			
		||||
                        /* Do it on a single node */
 | 
			
		||||
			char csid[MAX_CSID_LEN];
 | 
			
		||||
 | 
			
		||||
			if (csid_from_name(csid, inheader->node)) {
 | 
			
		||||
			if (clops->csid_from_name(csid, inheader->node)) {
 | 
			
		||||
				/* This has already been checked so should not happen */
 | 
			
		||||
				return 0;
 | 
			
		||||
			} else {
 | 
			
		||||
@@ -992,7 +1052,7 @@ static int distribute_command(struct local_client *thisfd)
 | 
			
		||||
				thisfd->bits.localsock.in_progress = TRUE;
 | 
			
		||||
 | 
			
		||||
				/* Are we the requested node ?? */
 | 
			
		||||
				if (memcmp(csid, our_csid, MAX_CSID_LEN) == 0) {
 | 
			
		||||
				if (memcmp(csid, our_csid, max_csid_len) == 0) {
 | 
			
		||||
					DEBUGLOG("Doing command on local node only\n");
 | 
			
		||||
					add_to_lvmqueue(thisfd, inheader, len, NULL);
 | 
			
		||||
				} else {
 | 
			
		||||
@@ -1024,17 +1084,17 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
 | 
			
		||||
			    char *csid)
 | 
			
		||||
{
 | 
			
		||||
	char *replyargs;
 | 
			
		||||
	char nodename[MAX_CLUSTER_MEMBER_NAME_LEN];
 | 
			
		||||
	char nodename[max_cluster_member_name_len];
 | 
			
		||||
	int replylen = 0;
 | 
			
		||||
	int buflen = MAX_CLUSTER_MESSAGE - sizeof(struct clvm_header) - 1;
 | 
			
		||||
	int buflen = max_cluster_message - sizeof(struct clvm_header) - 1;
 | 
			
		||||
	int status;
 | 
			
		||||
	int msg_malloced = 0;
 | 
			
		||||
 | 
			
		||||
	/* Get the node name as we /may/ need it later */
 | 
			
		||||
	name_from_csid(csid, nodename);
 | 
			
		||||
	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) {
 | 
			
		||||
@@ -1056,7 +1116,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;
 | 
			
		||||
@@ -1073,7 +1133,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;
 | 
			
		||||
@@ -1097,7 +1157,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
 | 
			
		||||
	if (msg->cmd == CLVMD_CMD_VERSION) {
 | 
			
		||||
		int *version_nums = (int *) msg->args;
 | 
			
		||||
		char node[256];
 | 
			
		||||
		name_from_csid(csid, node);
 | 
			
		||||
		clops->name_from_csid(csid, node);
 | 
			
		||||
		DEBUGLOG("Remote node %s is version %d.%d.%d\n",
 | 
			
		||||
			 node,
 | 
			
		||||
			 ntohl(version_nums[0]),
 | 
			
		||||
@@ -1118,17 +1178,17 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
 | 
			
		||||
			byebyemsg.flags = 0;
 | 
			
		||||
			byebyemsg.arglen = 0;
 | 
			
		||||
			byebyemsg.clientid = 0;
 | 
			
		||||
			cluster_send_message(&byebyemsg, sizeof(byebyemsg),
 | 
			
		||||
			clops->cluster_send_message(&byebyemsg, sizeof(byebyemsg),
 | 
			
		||||
					     our_csid,
 | 
			
		||||
					     "Error Sending GOAWAY message");
 | 
			
		||||
		} else {
 | 
			
		||||
			add_up_node(csid);
 | 
			
		||||
			clops->add_up_node(csid);
 | 
			
		||||
		}
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Allocate a default reply buffer */
 | 
			
		||||
	replyargs = malloc(MAX_CLUSTER_MESSAGE - sizeof(struct clvm_header));
 | 
			
		||||
	replyargs = malloc(max_cluster_message - sizeof(struct clvm_header));
 | 
			
		||||
 | 
			
		||||
	if (replyargs != NULL) {
 | 
			
		||||
		/* Run the command */
 | 
			
		||||
@@ -1136,7 +1196,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 */
 | 
			
		||||
@@ -1167,11 +1227,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,
 | 
			
		||||
				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,
 | 
			
		||||
@@ -1187,7 +1246,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 {
 | 
			
		||||
@@ -1196,7 +1255,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;
 | 
			
		||||
@@ -1228,13 +1287,13 @@ static void add_reply_to_list(struct local_client *client, int status,
 | 
			
		||||
	reply = malloc(sizeof(struct node_reply));
 | 
			
		||||
	if (reply) {
 | 
			
		||||
		reply->status = status;
 | 
			
		||||
		name_from_csid(csid, reply->node);
 | 
			
		||||
		clops->name_from_csid(csid, reply->node);
 | 
			
		||||
		DEBUGLOG("Reply from node %s: %d bytes\n", reply->node, len);
 | 
			
		||||
 | 
			
		||||
		if (len > 0) {
 | 
			
		||||
			reply->replymsg = malloc(len);
 | 
			
		||||
			if (!reply->replymsg) {
 | 
			
		||||
				reply->status = -ENOMEM;
 | 
			
		||||
				reply->status = ENOMEM;
 | 
			
		||||
			} else {
 | 
			
		||||
				memcpy(reply->replymsg, buf, len);
 | 
			
		||||
			}
 | 
			
		||||
@@ -1278,6 +1337,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);
 | 
			
		||||
@@ -1313,14 +1377,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);
 | 
			
		||||
@@ -1342,8 +1404,8 @@ static int process_local_command(struct clvm_header *msg, int msglen,
 | 
			
		||||
				 struct local_client *client,
 | 
			
		||||
				 unsigned short xid)
 | 
			
		||||
{
 | 
			
		||||
	char *replybuf = malloc(MAX_CLUSTER_MESSAGE);
 | 
			
		||||
	int buflen = MAX_CLUSTER_MESSAGE - sizeof(struct clvm_header) - 1;
 | 
			
		||||
	char *replybuf = malloc(max_cluster_message);
 | 
			
		||||
	int buflen = max_cluster_message - sizeof(struct clvm_header) - 1;
 | 
			
		||||
	int replylen = 0;
 | 
			
		||||
	int status;
 | 
			
		||||
 | 
			
		||||
@@ -1425,9 +1487,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;
 | 
			
		||||
 | 
			
		||||
@@ -1439,6 +1502,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);
 | 
			
		||||
 | 
			
		||||
@@ -1507,7 +1573,8 @@ static void send_version_message()
 | 
			
		||||
	version_nums[1] = htonl(CLVMD_MINOR_VERSION);
 | 
			
		||||
	version_nums[2] = htonl(CLVMD_PATCH_VERSION);
 | 
			
		||||
 | 
			
		||||
	cluster_send_message(message, sizeof(message), NULL,
 | 
			
		||||
	hton_clvm(msg);
 | 
			
		||||
	clops->cluster_send_message(message, sizeof(message), NULL,
 | 
			
		||||
			     "Error Sending version number");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1519,8 +1586,8 @@ 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 */
 | 
			
		||||
		return cluster_send_message(buf, msglen, csid, errtext);
 | 
			
		||||
		hton_clvm((struct clvm_header *) buf);
 | 
			
		||||
		return clops->cluster_send_message(buf, msglen, csid, errtext);
 | 
			
		||||
	} else {
 | 
			
		||||
		int ptr = 0;
 | 
			
		||||
 | 
			
		||||
@@ -1540,6 +1607,15 @@ 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);
 | 
			
		||||
		close(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,
 | 
			
		||||
@@ -1559,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);
 | 
			
		||||
@@ -1570,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 (;;) {
 | 
			
		||||
@@ -1590,6 +1671,7 @@ static void *lvm_thread_fn(void *arg)
 | 
			
		||||
			pthread_mutex_unlock(&lvm_thread_mutex);
 | 
			
		||||
 | 
			
		||||
			process_work_item(cmd);
 | 
			
		||||
			if (cmd->msg)
 | 
			
		||||
				free(cmd->msg);
 | 
			
		||||
			free(cmd);
 | 
			
		||||
 | 
			
		||||
@@ -1607,21 +1689,26 @@ 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;
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
		memcpy(cmd->csid, csid, max_csid_len);
 | 
			
		||||
		cmd->remote = 1;
 | 
			
		||||
	} else {
 | 
			
		||||
		cmd->remote = 0;
 | 
			
		||||
@@ -1652,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));
 | 
			
		||||
@@ -1689,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1699,7 +1788,7 @@ static void check_all_callback(struct local_client *client, char *csid,
 | 
			
		||||
static int check_all_clvmds_running(struct local_client *client)
 | 
			
		||||
{
 | 
			
		||||
	DEBUGLOG("check_all_clvmds_running\n");
 | 
			
		||||
	return cluster_do_node_callback(client, check_all_callback);
 | 
			
		||||
	return clops->cluster_do_node_callback(client, check_all_callback);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Return a local_client struct given a client ID.
 | 
			
		||||
@@ -1745,3 +1834,20 @@ static void sigterm_handler(int sig)
 | 
			
		||||
	quit = 1;
 | 
			
		||||
	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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int sync_unlock(const char *resource, int lockid)
 | 
			
		||||
{
 | 
			
		||||
	return clops->sync_unlock(resource, 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;
 | 
			
		||||
@@ -95,7 +96,7 @@ struct local_client {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
@@ -116,4 +117,8 @@ extern int add_client(struct local_client *new_client);
 | 
			
		||||
 | 
			
		||||
extern void clvmd_cluster_init_completed(void);
 | 
			
		||||
extern void process_message(struct local_client *client, char *buf, int len, char *csid);
 | 
			
		||||
 | 
			
		||||
int sync_lock(const char *resource, int mode, int flags, int *lockid);
 | 
			
		||||
int sync_unlock(const char *resource, int lockid);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -63,8 +63,8 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Maximum size of a cluster message */
 | 
			
		||||
#define MAX_CLUSTER_MESSAGE          1500
 | 
			
		||||
#define MAX_CLUSTER_MEMBER_NAME_LEN   255
 | 
			
		||||
#define CMAN_MAX_CLUSTER_MESSAGE          1500
 | 
			
		||||
#define CMAN_MAX_CLUSTER_MEMBER_NAME_LEN   255
 | 
			
		||||
#define MAX_BARRIER_NAME_LEN           33
 | 
			
		||||
#define MAX_SA_ADDR_LEN                12
 | 
			
		||||
#define MAX_CLUSTER_NAME_LEN           16
 | 
			
		||||
@@ -147,7 +147,7 @@ struct cl_cluster_node {
 | 
			
		||||
	unsigned int leave_reason;
 | 
			
		||||
	unsigned int incarnation;
 | 
			
		||||
	nodestate_t state;
 | 
			
		||||
	char name[MAX_CLUSTER_MEMBER_NAME_LEN];
 | 
			
		||||
	char name[CMAN_MAX_CLUSTER_MEMBER_NAME_LEN];
 | 
			
		||||
	unsigned char votes;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,9 @@
 | 
			
		||||
#include "list.h"
 | 
			
		||||
#include "locking.h"
 | 
			
		||||
#include "system-lv.h"
 | 
			
		||||
#include "clvm.h"
 | 
			
		||||
#include "clvmd-comms.h"
 | 
			
		||||
#include "clvmd.h"
 | 
			
		||||
#ifdef HAVE_CCS
 | 
			
		||||
#include "ccs.h"
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -96,19 +101,21 @@ void tcp_remove_client(char *csid)
 | 
			
		||||
       job of clvmd.c whch will do the job when it notices the
 | 
			
		||||
       other end has gone. We just need to remove the client(s) from
 | 
			
		||||
       the hash table so we don't try to use it for sending any more */
 | 
			
		||||
    client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
 | 
			
		||||
    client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
 | 
			
		||||
    if (client)
 | 
			
		||||
    {
 | 
			
		||||
	hash_remove_binary(sock_hash, csid, MAX_CSID_LEN);
 | 
			
		||||
	hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
 | 
			
		||||
	client->removeme = 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Look for a mangled one too */
 | 
			
		||||
    csid[0] ^= 0x80;
 | 
			
		||||
 | 
			
		||||
    client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
 | 
			
		||||
    client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
 | 
			
		||||
    if (client)
 | 
			
		||||
    {
 | 
			
		||||
	hash_remove_binary(sock_hash, csid, MAX_CSID_LEN);
 | 
			
		||||
	hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
 | 
			
		||||
	client->removeme = 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Put it back as we found it */
 | 
			
		||||
@@ -137,7 +144,7 @@ int alloc_client(int fd, char *csid, struct local_client **new_client)
 | 
			
		||||
	*new_client = client;
 | 
			
		||||
 | 
			
		||||
    /* Add to our list of node sockets */
 | 
			
		||||
    if (hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN))
 | 
			
		||||
    if (hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN))
 | 
			
		||||
    {
 | 
			
		||||
	DEBUGLOG("alloc_client mangling CSID for second connection\n");
 | 
			
		||||
	/* This is a duplicate connection but we can't close it because
 | 
			
		||||
@@ -150,7 +157,7 @@ int alloc_client(int fd, char *csid, struct local_client **new_client)
 | 
			
		||||
 | 
			
		||||
        /* If it still exists then kill the connection as we should only
 | 
			
		||||
           ever have one incoming connection from each node */
 | 
			
		||||
        if (hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN))
 | 
			
		||||
        if (hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN))
 | 
			
		||||
        {
 | 
			
		||||
	    DEBUGLOG("Multiple incoming connections from node\n");
 | 
			
		||||
            syslog(LOG_ERR, " Bogus incoming connection from %d.%d.%d.%d\n", csid[0],csid[1],csid[2],csid[3]);
 | 
			
		||||
@@ -160,26 +167,26 @@ int alloc_client(int fd, char *csid, struct local_client **new_client)
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    hash_insert_binary(sock_hash, csid, MAX_CSID_LEN, client);
 | 
			
		||||
    hash_insert_binary(sock_hash, csid, GULM_MAX_CSID_LEN, client);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_main_cluster_fd()
 | 
			
		||||
int get_main_gulm_cluster_fd()
 | 
			
		||||
{
 | 
			
		||||
    return listen_fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Read on main comms (listen) socket, accept it */
 | 
			
		||||
int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
 | 
			
		||||
int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, char *csid,
 | 
			
		||||
			struct local_client **new_client)
 | 
			
		||||
{
 | 
			
		||||
    int newfd;
 | 
			
		||||
    struct sockaddr_in6 addr;
 | 
			
		||||
    socklen_t addrlen = sizeof(addr);
 | 
			
		||||
    int status;
 | 
			
		||||
    char name[MAX_CLUSTER_MEMBER_NAME_LEN];
 | 
			
		||||
    char name[GULM_MAX_CLUSTER_MEMBER_NAME_LEN];
 | 
			
		||||
 | 
			
		||||
    DEBUGLOG("cluster_fd_callback\n");
 | 
			
		||||
    *new_client = NULL;
 | 
			
		||||
@@ -196,7 +203,7 @@ int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
 | 
			
		||||
    /* Check that the client is a member of the cluster
 | 
			
		||||
       and reject if not.
 | 
			
		||||
    */
 | 
			
		||||
    if (name_from_csid((char *)&addr.sin6_addr, name) < 0)
 | 
			
		||||
    if (gulm_name_from_csid((char *)&addr.sin6_addr, name) < 0)
 | 
			
		||||
    {
 | 
			
		||||
	syslog(LOG_ERR, "Got connect from non-cluster node %s\n",
 | 
			
		||||
	       print_csid((char *)&addr.sin6_addr));
 | 
			
		||||
@@ -227,16 +234,37 @@ static int read_from_tcpsock(struct local_client *client, char *buf, int len, ch
 | 
			
		||||
{
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    /* Get "csid" */
 | 
			
		||||
    getpeername(client->fd, (struct sockaddr *)&addr, &slen);
 | 
			
		||||
    memcpy(csid, &addr.sin6_addr, MAX_CSID_LEN);
 | 
			
		||||
    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 = 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 = 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);
 | 
			
		||||
 | 
			
		||||
@@ -245,31 +273,33 @@ static int read_from_tcpsock(struct local_client *client, char *buf, int len, ch
 | 
			
		||||
    if (status == 0 ||
 | 
			
		||||
	(status < 0 && errno != EAGAIN && errno != EINTR))
 | 
			
		||||
    {
 | 
			
		||||
	char remcsid[MAX_CSID_LEN];
 | 
			
		||||
	char remcsid[GULM_MAX_CSID_LEN];
 | 
			
		||||
 | 
			
		||||
	memcpy(remcsid, csid, MAX_CSID_LEN);
 | 
			
		||||
	memcpy(remcsid, csid, GULM_MAX_CSID_LEN);
 | 
			
		||||
	close(client->fd);
 | 
			
		||||
 | 
			
		||||
	/* If the csid was mangled, then make sure we remove the right entry */
 | 
			
		||||
	if (client->bits.net.flags)
 | 
			
		||||
	    remcsid[0] ^= 0x80;
 | 
			
		||||
	hash_remove_binary(sock_hash, remcsid, MAX_CSID_LEN);
 | 
			
		||||
	hash_remove_binary(sock_hash, remcsid, GULM_MAX_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
	/* Tell cluster manager layer */
 | 
			
		||||
	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);
 | 
			
		||||
@@ -281,18 +311,28 @@ static int connect_csid(char *csid, struct local_client **newclient)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    addr.sin6_family = AF_INET6;
 | 
			
		||||
    memcpy(&addr.sin6_addr, csid, MAX_CSID_LEN);
 | 
			
		||||
    memcpy(&addr.sin6_addr, csid, GULM_MAX_CSID_LEN);
 | 
			
		||||
    addr.sin6_port = htons(tcp_port);
 | 
			
		||||
 | 
			
		||||
    DEBUGLOG("Connecting socket %d\n", fd);
 | 
			
		||||
    if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0)
 | 
			
		||||
    {
 | 
			
		||||
	/* "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);
 | 
			
		||||
@@ -300,7 +340,7 @@ static int connect_csid(char *csid, struct local_client **newclient)
 | 
			
		||||
	add_client(*newclient);
 | 
			
		||||
 | 
			
		||||
    /* If we can connect to it, it must be running a clvmd */
 | 
			
		||||
    add_up_node(csid);
 | 
			
		||||
    gulm_add_up_node(csid);
 | 
			
		||||
    return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -309,21 +349,21 @@ static int tcp_send_message(void *buf, int msglen, unsigned char *csid, const ch
 | 
			
		||||
{
 | 
			
		||||
    int status;
 | 
			
		||||
    struct local_client *client;
 | 
			
		||||
    char ourcsid[MAX_CSID_LEN];
 | 
			
		||||
    char ourcsid[GULM_MAX_CSID_LEN];
 | 
			
		||||
 | 
			
		||||
    assert(csid);
 | 
			
		||||
 | 
			
		||||
    DEBUGLOG("tcp_send_message, csid = %s, msglen = %d\n", print_csid(csid), msglen);
 | 
			
		||||
 | 
			
		||||
    /* Don't connect to ourself */
 | 
			
		||||
    get_our_csid(ourcsid);
 | 
			
		||||
    if (memcmp(csid, ourcsid, MAX_CSID_LEN) == 0)
 | 
			
		||||
    get_our_gulm_csid(ourcsid);
 | 
			
		||||
    if (memcmp(csid, ourcsid, GULM_MAX_CSID_LEN) == 0)
 | 
			
		||||
	return msglen;
 | 
			
		||||
 | 
			
		||||
    client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
@@ -333,7 +373,7 @@ static int tcp_send_message(void *buf, int msglen, unsigned char *csid, const ch
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
 | 
			
		||||
int gulm_cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
 | 
			
		||||
{
 | 
			
		||||
    int status=0;
 | 
			
		||||
 | 
			
		||||
@@ -343,7 +383,7 @@ int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
 | 
			
		||||
    if (!csid)
 | 
			
		||||
    {
 | 
			
		||||
	void *context = NULL;
 | 
			
		||||
	char loop_csid[MAX_CSID_LEN];
 | 
			
		||||
	char loop_csid[GULM_MAX_CSID_LEN];
 | 
			
		||||
 | 
			
		||||
	/* Loop round all gulm-known nodes */
 | 
			
		||||
	while (get_next_node_csid(&context, loop_csid))
 | 
			
		||||
@@ -377,9 +417,9 @@ static int get_our_ip_address(char *addr, int *family)
 | 
			
		||||
 | 
			
		||||
/* Public version of above for those that don't care what protocol
 | 
			
		||||
   we're using */
 | 
			
		||||
void get_our_csid(char *csid)
 | 
			
		||||
void get_our_gulm_csid(char *csid)
 | 
			
		||||
{
 | 
			
		||||
    static char our_csid[MAX_CSID_LEN];
 | 
			
		||||
    static char our_csid[GULM_MAX_CSID_LEN];
 | 
			
		||||
    static int got_csid = 0;
 | 
			
		||||
 | 
			
		||||
    if (!got_csid)
 | 
			
		||||
@@ -392,7 +432,7 @@ void get_our_csid(char *csid)
 | 
			
		||||
	    got_csid = 1;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    memcpy(csid, our_csid, MAX_CSID_LEN);
 | 
			
		||||
    memcpy(csid, our_csid, GULM_MAX_CSID_LEN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void map_v4_to_v6(struct in_addr *ip4, struct in6_addr *ip6)
 | 
			
		||||
@@ -408,7 +448,7 @@ int get_ip_address(char *node, char *addr)
 | 
			
		||||
{
 | 
			
		||||
    struct hostent *he;
 | 
			
		||||
 | 
			
		||||
    memset(addr, 0, MAX_CSID_LEN);
 | 
			
		||||
    memset(addr, 0, GULM_MAX_CSID_LEN);
 | 
			
		||||
 | 
			
		||||
    // TODO: what do we do about multi-homed hosts ???
 | 
			
		||||
    // CCSs ip_interfaces solved this but some bugger removed it.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,13 @@
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
 | 
			
		||||
#define MAX_CLUSTER_MESSAGE 1600
 | 
			
		||||
#define MAX_CSID_LEN sizeof(struct in6_addr)
 | 
			
		||||
#define MAX_CLUSTER_MEMBER_NAME_LEN 128
 | 
			
		||||
#define GULM_MAX_CLUSTER_MESSAGE 1600
 | 
			
		||||
#define GULM_MAX_CSID_LEN sizeof(struct in6_addr)
 | 
			
		||||
#define GULM_MAX_CLUSTER_MEMBER_NAME_LEN 128
 | 
			
		||||
 | 
			
		||||
extern int init_comms(unsigned short);
 | 
			
		||||
extern char *print_csid(char *);
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
ifeq ("@LIB_SUFFIX@","dylib")
 | 
			
		||||
  LIB_SHARED = libdmeventnoop.dylib
 | 
			
		||||
else
 | 
			
		||||
  LIB_SHARED = libdmeventnoop.so
 | 
			
		||||
endif
 | 
			
		||||
 
 | 
			
		||||
LDFLAGS += -ldl -ldevmapper -lpthread
 | 
			
		||||
 | 
			
		||||
include ../make.tmpl
 | 
			
		||||
 | 
			
		||||
libdmeventnoop.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 -lmultilog -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 -lmultilog $(LIBS)
 | 
			
		||||
 | 
			
		||||
install: $(INSTALL_TYPE)
 | 
			
		||||
 | 
			
		||||
.PHONY: install_dynamic
 | 
			
		||||
 | 
			
		||||
install_dynamic: dmeventd
 | 
			
		||||
	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) dmeventd $(sbindir)/dmeventd
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										137
									
								
								daemons/dmeventd/dmevent.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								daemons/dmeventd/dmevent.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,137 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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 <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 */
 | 
			
		||||
 | 
			
		||||
/* 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"
 | 
			
		||||
	       "  -u                 Unregister for event.\n"
 | 
			
		||||
	       "\n", cmd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Parse command line arguments. */
 | 
			
		||||
static int parse_argv(int argc, char **argv,
 | 
			
		||||
		      char **dso_name, char **device, int *reg, int *list)
 | 
			
		||||
{
 | 
			
		||||
	int c;
 | 
			
		||||
	const char *options = "d:hlru";
 | 
			
		||||
 | 
			
		||||
	while ((c = getopt(argc, argv, options)) != -1) {
 | 
			
		||||
		switch (c) {
 | 
			
		||||
		case 'd':
 | 
			
		||||
			*dso_name = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'h':
 | 
			
		||||
			print_usage(argv[0]);
 | 
			
		||||
			exit(EXIT_SUCCESS);
 | 
			
		||||
		case 'l':
 | 
			
		||||
			*list = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'r':
 | 
			
		||||
			*reg = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'u':
 | 
			
		||||
			*reg = 0;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			fprintf(stderr, "Unknown option '%c'.\n"
 | 
			
		||||
				"Try '-h' for help.\n", c);
 | 
			
		||||
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!*list) {
 | 
			
		||||
		if (optind >= argc) {
 | 
			
		||||
			fprintf(stderr, "You need to specify a device.\n");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		*device = argv[optind];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	int list = 0, ret, reg = default_reg;
 | 
			
		||||
	char *device, *dso_name = default_dso_name;
 | 
			
		||||
 | 
			
		||||
	if (!parse_argv(argc, argv, &dso_name, &device, ®, &list))
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	
 | 
			
		||||
	if (list) {
 | 
			
		||||
		do {
 | 
			
		||||
			ret = dm_get_next_registered_device(&dso_name, &device, &events);
 | 
			
		||||
			if (!ret) {
 | 
			
		||||
				printf("%s %s 0x%x\n", dso_name, device, events);
 | 
			
		||||
				free(dso_name);
 | 
			
		||||
				free(device);
 | 
			
		||||
			}
 | 
			
		||||
		} while (ret);
 | 
			
		||||
 | 
			
		||||
		exit(EXIT_SUCCESS);
 | 
			
		||||
	}
 | 
			
		||||
	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));
 | 
			
		||||
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printf("%s %sregistered successfully.\n", device, reg ? "" : "un");
 | 
			
		||||
 | 
			
		||||
	exit(EXIT_SUCCESS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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:
 | 
			
		||||
 */
 | 
			
		||||
							
								
								
									
										1021
									
								
								daemons/dmeventd/dmeventd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1021
									
								
								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 <stdio.h>
 | 
			
		||||
 | 
			
		||||
void process_event(char *device, enum event_type event)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(stderr, "[%s] %s(%d) - Device: %s, Event %d\n",
 | 
			
		||||
		__FILE__, __func__, __LINE__, device, event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int register_device(char *device)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(stderr, "[%s] %s(%d) - Device: %s\n",
 | 
			
		||||
		__FILE__, __func__, __LINE__, device);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int unregister_device(char *device)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(stderr, "[%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
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,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
 | 
			
		||||
 
 | 
			
		||||
@@ -70,6 +70,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 \
 | 
			
		||||
 
 | 
			
		||||
@@ -78,12 +78,13 @@ int target_present(const char *target_name)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
int lv_info(const struct logical_volume *lv, struct lvinfo *info)
 | 
			
		||||
int lv_info(const struct logical_volume *lv, struct lvinfo *info,
 | 
			
		||||
	    int with_open_count)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
 | 
			
		||||
		    struct lvinfo *info)
 | 
			
		||||
		    struct lvinfo *info, int with_open_count)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -333,7 +334,7 @@ int target_present(const char *target_name)
 | 
			
		||||
 * Returns 1 if info structure populated, else 0 on failure.
 | 
			
		||||
 */
 | 
			
		||||
static int _lv_info(const struct logical_volume *lv, int mknodes,
 | 
			
		||||
		    struct lvinfo *info)
 | 
			
		||||
		    struct lvinfo *info, int with_open_count)
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
	struct dev_manager *dm;
 | 
			
		||||
@@ -347,7 +348,7 @@ static int _lv_info(const struct logical_volume *lv, int mknodes,
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(r = dev_manager_info(dm, lv, mknodes, &dminfo)))
 | 
			
		||||
	if (!(r = dev_manager_info(dm, lv, mknodes, with_open_count, &dminfo)))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	info->exists = dminfo.exists;
 | 
			
		||||
@@ -361,20 +362,21 @@ static int _lv_info(const struct logical_volume *lv, int mknodes,
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lv_info(const struct logical_volume *lv, struct lvinfo *info)
 | 
			
		||||
int lv_info(const struct logical_volume *lv, struct lvinfo *info,
 | 
			
		||||
	    int with_open_count)
 | 
			
		||||
{
 | 
			
		||||
	return _lv_info(lv, 0, info);
 | 
			
		||||
	return _lv_info(lv, 0, info, with_open_count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
 | 
			
		||||
		    struct lvinfo *info)
 | 
			
		||||
		    struct lvinfo *info, int with_open_count)
 | 
			
		||||
{
 | 
			
		||||
	struct logical_volume *lv;
 | 
			
		||||
 | 
			
		||||
	if (!(lv = lv_from_lvid(cmd, lvid_s)))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	return _lv_info(lv, 0, info);
 | 
			
		||||
	return _lv_info(lv, 0, info, with_open_count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -412,7 +414,7 @@ int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
 | 
			
		||||
	if (!activation())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
	if (!lv_info(lv, &info, 0)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -437,7 +439,7 @@ static int _lv_active(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	struct lvinfo info;
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
	if (!lv_info(lv, &info, 0)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
@@ -449,7 +451,7 @@ static int _lv_open_count(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	struct lvinfo info;
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
	if (!lv_info(lv, &info, 1)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
@@ -566,7 +568,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
	if (!lv_info(lv, &info, 0)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -612,7 +614,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
	if (!lv_info(lv, &info, 0)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -657,7 +659,7 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
	if (!lv_info(lv, &info, 1)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -726,7 +728,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, int filter)
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lv_info(lv, &info)) {
 | 
			
		||||
	if (!lv_info(lv, &info, 0)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -765,7 +767,7 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_lv_info(lv, 1, &info)) {
 | 
			
		||||
	if (!_lv_info(lv, 1, &info, 0)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -55,9 +55,10 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
 | 
			
		||||
/*
 | 
			
		||||
 * Returns 1 if info structure has been populated, else 0.
 | 
			
		||||
 */
 | 
			
		||||
int lv_info(const struct logical_volume *lv, struct lvinfo *info);
 | 
			
		||||
int lv_info(const struct logical_volume *lv, struct lvinfo *info,
 | 
			
		||||
	    int with_open_count);
 | 
			
		||||
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
 | 
			
		||||
		    struct lvinfo *info);
 | 
			
		||||
		    struct lvinfo *info, int with_open_count);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Returns 1 if activate_lv has been set: 1 = activate; 0 = don't.
 | 
			
		||||
 
 | 
			
		||||
@@ -211,7 +211,8 @@ static struct dm_task *_setup_task(const char *name, const char *uuid,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _info_run(const char *name, const char *uuid, struct dm_info *info,
 | 
			
		||||
		     int mknodes, struct pool *mem, char **uuid_out)
 | 
			
		||||
		     int mknodes, int with_open_count, struct pool *mem,
 | 
			
		||||
		     char **uuid_out)
 | 
			
		||||
{
 | 
			
		||||
	int r = 0;
 | 
			
		||||
	struct dm_task *dmt;
 | 
			
		||||
@@ -225,6 +226,10 @@ static int _info_run(const char *name, const char *uuid, struct dm_info *info,
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!with_open_count)
 | 
			
		||||
		if (!dm_task_no_open_count(dmt))
 | 
			
		||||
			log_error("Failed to disable open_count");
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_run(dmt)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
@@ -250,14 +255,17 @@ static int _info_run(const char *name, const char *uuid, struct dm_info *info,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _info(const char *name, const char *uuid, int mknodes,
 | 
			
		||||
		 struct dm_info *info, struct pool *mem, char **uuid_out)
 | 
			
		||||
		 int with_open_count, struct dm_info *info,
 | 
			
		||||
		 struct pool *mem, char **uuid_out)
 | 
			
		||||
{
 | 
			
		||||
	if (!mknodes && uuid && *uuid &&
 | 
			
		||||
	    _info_run(NULL, uuid, info, 0, mem, uuid_out) && info->exists)
 | 
			
		||||
	    _info_run(NULL, uuid, info, 0, with_open_count, mem, uuid_out) &&
 | 
			
		||||
	    	      info->exists)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (name)
 | 
			
		||||
		return _info_run(name, NULL, info, mknodes, mem, uuid_out);
 | 
			
		||||
		return _info_run(name, NULL, info, mknodes, with_open_count,
 | 
			
		||||
				 mem, uuid_out);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -279,6 +287,9 @@ static int _status_run(const char *name, const char *uuid,
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_no_open_count(dmt))
 | 
			
		||||
		log_error("Failed to disable open_count");
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_run(dmt)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
@@ -357,6 +368,9 @@ static int _percent_run(struct dev_manager *dm, const char *name,
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_no_open_count(dmt))
 | 
			
		||||
		log_error("Failed to disable open_count");
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_run(dmt)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		goto out;
 | 
			
		||||
@@ -460,6 +474,9 @@ static int _rename(struct dev_manager *dm, struct dev_layer *dl, char *newname)
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_no_open_count(dmt))
 | 
			
		||||
		log_error("Failed to disable open_count");
 | 
			
		||||
 | 
			
		||||
	if (!(r = dm_task_run(dmt))) {
 | 
			
		||||
		log_error("Couldn't rename device '%s'.", dl->name);
 | 
			
		||||
		goto out;
 | 
			
		||||
@@ -488,6 +505,9 @@ static int _suspend_or_resume(const char *name, action_t suspend)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_no_open_count(dmt))
 | 
			
		||||
		log_error("Failed to disable open_count");
 | 
			
		||||
 | 
			
		||||
	if (!(r = dm_task_run(dmt)))
 | 
			
		||||
		log_error("Couldn't %s device '%s'", sus ? "suspend" : "resume",
 | 
			
		||||
			  name);
 | 
			
		||||
@@ -579,6 +599,9 @@ static int _load(struct dev_manager *dm, struct dev_layer *dl, int task)
 | 
			
		||||
			log_very_verbose("Activating %s read-only", dl->name);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_no_open_count(dmt))
 | 
			
		||||
		log_error("Failed to disable open_count");
 | 
			
		||||
 | 
			
		||||
	if (!(r = dm_task_run(dmt))) {
 | 
			
		||||
		log_error("Couldn't load device '%s'.", dl->name);
 | 
			
		||||
		if ((dl->lv->minor >= 0 || dl->lv->major >= 0) &&
 | 
			
		||||
@@ -635,6 +658,9 @@ static int _remove(struct dev_layer *dl)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!dm_task_no_open_count(dmt))
 | 
			
		||||
		log_error("Failed to disable open_count");
 | 
			
		||||
 | 
			
		||||
	/* Suppress error message if it's still in use - we'll log it later */
 | 
			
		||||
	log_suppress(1);
 | 
			
		||||
 | 
			
		||||
@@ -701,6 +727,25 @@ 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;
 | 
			
		||||
 | 
			
		||||
	tw = lvm_snprintf(params, paramsize, "core 1 %u %u ",
 | 
			
		||||
			  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)
 | 
			
		||||
@@ -849,21 +894,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;
 | 
			
		||||
	}
 | 
			
		||||
@@ -882,27 +929,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;
 | 
			
		||||
	}
 | 
			
		||||
@@ -970,7 +1017,7 @@ void dev_manager_destroy(struct dev_manager *dm)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
 | 
			
		||||
		     int mknodes, struct dm_info *info)
 | 
			
		||||
		     int mknodes, int with_open_count, struct dm_info *info)
 | 
			
		||||
{
 | 
			
		||||
	char *name;
 | 
			
		||||
 | 
			
		||||
@@ -986,7 +1033,8 @@ int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
 | 
			
		||||
	 * Try and get some info on this device.
 | 
			
		||||
	 */
 | 
			
		||||
	log_debug("Getting device info for %s", name);
 | 
			
		||||
	if (!_info(name, lv->lvid.s, mknodes, info, NULL, NULL)) {
 | 
			
		||||
	if (!_info(name, lv->lvid.s, mknodes, with_open_count, info, NULL,
 | 
			
		||||
		   NULL)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -1065,7 +1113,7 @@ static struct dev_layer *_create_dev(struct dev_manager *dm, char *name,
 | 
			
		||||
	dl->name = name;
 | 
			
		||||
 | 
			
		||||
	log_debug("Getting device info for %s", dl->name);
 | 
			
		||||
	if (!_info(dl->name, dlid, 0, &dl->info, dm->mem, &uuid)) {
 | 
			
		||||
	if (!_info(dl->name, dlid, 0, 0, &dl->info, dm->mem, &uuid)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
@@ -1246,7 +1294,7 @@ 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 lv_segment *snap_seg;
 | 
			
		||||
	struct list *sh;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
@@ -1255,7 +1303,7 @@ static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv)
 | 
			
		||||
	 */
 | 
			
		||||
	list_iterate(sh, &dm->active_list) {
 | 
			
		||||
		active = list_item(sh, struct lv_list)->lv;
 | 
			
		||||
		if ((s = find_cow(active)) && (s->origin == lv))
 | 
			
		||||
		if ((snap_seg = find_cow(active)) && (snap_seg->origin == lv))
 | 
			
		||||
			return _expand_origin_real(dm, lv);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -1266,7 +1314,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)
 | 
			
		||||
@@ -1303,13 +1351,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;
 | 
			
		||||
	}
 | 
			
		||||
@@ -1322,13 +1372,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);
 | 
			
		||||
@@ -1417,6 +1467,8 @@ static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag)
 | 
			
		||||
 | 
			
		||||
	list_iterate(lvh, lvs) {
 | 
			
		||||
		lv = list_item(lvh, struct lv_list)->lv;
 | 
			
		||||
		if (lv->status & SNAPSHOT)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!(dl = _lookup(dm, lv->lvid.s, NULL))) {
 | 
			
		||||
			stack;
 | 
			
		||||
@@ -1578,14 +1630,16 @@ 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 logical_volume *lv;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Build layers for complete vg.
 | 
			
		||||
	 */
 | 
			
		||||
	list_iterate(lvh, &vg->lvs) {
 | 
			
		||||
		lvt = list_item(lvh, struct lv_list)->lv;
 | 
			
		||||
		if (!_expand_lv(dm, lvt)) {
 | 
			
		||||
		lv = list_item(lvh, struct lv_list)->lv;
 | 
			
		||||
		if (lv->status & SNAPSHOT)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (!_expand_lv(dm, lv)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
@@ -1887,12 +1941,14 @@ static int _add_lvs(struct pool *mem,
 | 
			
		||||
		    struct list *head, struct logical_volume *origin)
 | 
			
		||||
{
 | 
			
		||||
	struct logical_volume *lv;
 | 
			
		||||
	struct snapshot *s;
 | 
			
		||||
	struct lv_segment *snap_seg;
 | 
			
		||||
	struct list *lvh;
 | 
			
		||||
 | 
			
		||||
	list_iterate(lvh, &origin->vg->lvs) {
 | 
			
		||||
		lv = list_item(lvh, struct lv_list)->lv;
 | 
			
		||||
		if ((s = find_cow(lv)) && s->origin == origin)
 | 
			
		||||
		if (lv->status & SNAPSHOT)
 | 
			
		||||
			continue;
 | 
			
		||||
		if ((snap_seg = find_cow(lv)) && snap_seg->origin == origin)
 | 
			
		||||
			if (!_add_lv(mem, head, lv))
 | 
			
		||||
				return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -1917,7 +1973,7 @@ 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 lv_segment *snap_seg;
 | 
			
		||||
	struct list *sh, *active_head;
 | 
			
		||||
 | 
			
		||||
	active_head = &dm->active_list;
 | 
			
		||||
@@ -1925,22 +1981,23 @@ static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv)
 | 
			
		||||
	/* 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) {
 | 
			
		||||
		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) {
 | 
			
		||||
		if ((snap_seg = find_cow(active)) &&
 | 
			
		||||
		    snap_seg->origin == old_origin) {
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -1952,7 +2009,7 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
 | 
			
		||||
				 struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	struct logical_volume *suspended;
 | 
			
		||||
	struct snapshot *s;
 | 
			
		||||
	struct lv_segment *snap_seg;
 | 
			
		||||
	struct list *sh, *suspend_head;
 | 
			
		||||
 | 
			
		||||
	suspend_head = &dm->suspend_list;
 | 
			
		||||
@@ -1960,7 +2017,8 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
 | 
			
		||||
	/* 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) {
 | 
			
		||||
		if ((snap_seg = find_cow(suspended)) &&
 | 
			
		||||
		    snap_seg->origin == lv) {
 | 
			
		||||
			_remove_lv(suspend_head, suspended);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -2046,6 +2104,8 @@ static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
 | 
			
		||||
 | 
			
		||||
	list_iterate(lvh, &vg->lvs) {
 | 
			
		||||
		lv = list_item(lvh, struct lv_list)->lv;
 | 
			
		||||
		if (lv->status & SNAPSHOT)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) {
 | 
			
		||||
			stack;
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@ void dev_manager_exit(void);
 | 
			
		||||
 * unsuspended until the snapshot is also created.)
 | 
			
		||||
 */
 | 
			
		||||
int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
 | 
			
		||||
		     int mknodes, struct dm_info *info);
 | 
			
		||||
		     int mknodes, int with_open_count, struct dm_info *info);
 | 
			
		||||
int dev_manager_snapshot_percent(struct dev_manager *dm,
 | 
			
		||||
				 struct logical_volume *lv, float *percent);
 | 
			
		||||
int dev_manager_mirror_percent(struct dev_manager *dm,
 | 
			
		||||
 
 | 
			
		||||
@@ -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 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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								lib/cache/lvmcache.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								lib/cache/lvmcache.c
									
									
									
									
										vendored
									
									
								
							@@ -104,10 +104,30 @@ struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname)
 | 
			
		||||
const struct format_type *fmt_from_vgname(const char *vgname)
 | 
			
		||||
{
 | 
			
		||||
	struct lvmcache_vginfo *vginfo;
 | 
			
		||||
	struct label *label;
 | 
			
		||||
	struct list *ih, *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(ih, &vginfo->infos) {
 | 
			
		||||
		devl = malloc(sizeof(*devl));
 | 
			
		||||
		devl->dev = list_item(ih, struct lvmcache_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);
 | 
			
		||||
		free(devl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return vginfo->fmt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -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;
 | 
			
		||||
	}
 | 
			
		||||
@@ -266,7 +286,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,6 +423,9 @@ 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -551,6 +574,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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -181,6 +181,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",
 | 
			
		||||
@@ -825,8 +831,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");
 | 
			
		||||
 
 | 
			
		||||
@@ -32,17 +32,15 @@ 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;
 | 
			
		||||
 
 | 
			
		||||
@@ -95,15 +95,18 @@
 | 
			
		||||
#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_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,127 @@ 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 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)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
@@ -186,7 +187,7 @@ 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;
 | 
			
		||||
			log_debug("%s: Already in device cache", path);
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -355,11 +356,11 @@ 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;
 | 
			
		||||
 | 
			
		||||
	if (_cache.has_scanned)
 | 
			
		||||
	if (_cache.has_scanned && !dev_scan)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	list_iterate(dh, &_cache.dirs) {
 | 
			
		||||
@@ -368,6 +369,7 @@ static void _full_scan(void)
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	_cache.has_scanned = 1;
 | 
			
		||||
	init_full_scan_done(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_cache_has_scanned(void)
 | 
			
		||||
@@ -379,15 +381,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;
 | 
			
		||||
@@ -540,7 +541,7 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
 | 
			
		||||
	return (d && (!f || 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 +550,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;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ 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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -330,8 +330,13 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef O_DIRECT_SUPPORT
 | 
			
		||||
	if (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 +346,31 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if ((dev->fd = open(name, flags, 0777)) < 0) {
 | 
			
		||||
#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 +394,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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -317,7 +317,7 @@ void lvdisplay_colons(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	int inkernel;
 | 
			
		||||
	struct lvinfo info;
 | 
			
		||||
	inkernel = lv_info(lv, &info) && info.exists;
 | 
			
		||||
	inkernel = lv_info(lv, &info, 1) && info.exists;
 | 
			
		||||
 | 
			
		||||
	log_print("%s%s/%s:%s:%d:%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:%d:%d",
 | 
			
		||||
		  lv->vg->cmd->dev_dir,
 | 
			
		||||
@@ -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))) {
 | 
			
		||||
@@ -348,7 +347,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inkernel = lv_info(lv, &info) && info.exists;
 | 
			
		||||
	inkernel = lv_info(lv, &info, 1) && info.exists;
 | 
			
		||||
 | 
			
		||||
	log_print("--- Logical volume ---");
 | 
			
		||||
 | 
			
		||||
@@ -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_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);
 | 
			
		||||
 | 
			
		||||
@@ -550,7 +536,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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -148,7 +148,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))
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@
 | 
			
		||||
#include "filter.h"
 | 
			
		||||
#include "toolcontext.h"
 | 
			
		||||
#include "segtype.h"
 | 
			
		||||
#include "pv_alloc.h"
 | 
			
		||||
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
@@ -89,6 +90,13 @@ int import_pv(struct pool *mem, struct device *dev,
 | 
			
		||||
	pv->pe_alloc_count = pvd->pe_allocated;
 | 
			
		||||
 | 
			
		||||
	list_init(&pv->tags);
 | 
			
		||||
	list_init(&pv->segments);
 | 
			
		||||
	list_init(&pv->free_segments);
 | 
			
		||||
 | 
			
		||||
	if (!alloc_pv_segment_whole_pv(mem, pv)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -323,6 +331,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);
 | 
			
		||||
 | 
			
		||||
@@ -495,7 +505,7 @@ 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 list *lvh;
 | 
			
		||||
	struct lv_list *ll;
 | 
			
		||||
	struct lvd_list *lvdl;
 | 
			
		||||
	size_t len;
 | 
			
		||||
@@ -524,6 +534,9 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
 | 
			
		||||
 | 
			
		||||
	list_iterate(lvh, &vg->lvs) {
 | 
			
		||||
		ll = list_item(lvh, struct lv_list);
 | 
			
		||||
		if (ll->lv->status & SNAPSHOT)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			goto out;
 | 
			
		||||
@@ -532,7 +545,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 +557,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:
 | 
			
		||||
@@ -646,7 +641,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;
 | 
			
		||||
 
 | 
			
		||||
@@ -60,6 +60,8 @@ static struct hash_table *_create_lv_maps(struct pool *mem,
 | 
			
		||||
 | 
			
		||||
	list_iterate(llh, &vg->lvs) {
 | 
			
		||||
		ll = list_item(llh, struct lv_list);
 | 
			
		||||
		if (ll->lv->status & SNAPSHOT)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!(lvm = pool_alloc(mem, sizeof(*lvm)))) {
 | 
			
		||||
			stack;
 | 
			
		||||
@@ -205,58 +207,55 @@ 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;
 | 
			
		||||
 | 
			
		||||
	while (le < lvm->lv->le_count) {
 | 
			
		||||
		seg = alloc_lv_segment(cmd->mem, 1);
 | 
			
		||||
 | 
			
		||||
		seg->lv = lvm->lv;
 | 
			
		||||
		if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
 | 
			
		||||
	if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		seg->le = le;
 | 
			
		||||
		seg->len = 0;
 | 
			
		||||
		seg->area_len = 0;
 | 
			
		||||
		seg->stripe_size = 0;
 | 
			
		||||
	while (le < lvm->lv->le_count) {
 | 
			
		||||
		len = 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
 | 
			
		||||
			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));
 | 
			
		||||
 | 
			
		||||
		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));
 | 
			
		||||
		if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le,
 | 
			
		||||
					     len, 0, 0, 1, len, 0, 0))) {
 | 
			
		||||
			log_error("Failed to allocate linear segment.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		le += seg->len;
 | 
			
		||||
		set_lv_segment_area_pv(seg, 0, lvm->map[le].pv, lvm->map[le].pe);
 | 
			
		||||
 | 
			
		||||
		list_add(&lvm->lv->segments, &seg->list);
 | 
			
		||||
 | 
			
		||||
		le += seg->len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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 +263,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 +277,42 @@ 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, lvm->stripes,
 | 
			
		||||
					     area_len, 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++)
 | 
			
		||||
			set_lv_segment_area_pv(seg, st,
 | 
			
		||||
					       lvm->map[le + st * len].pv,
 | 
			
		||||
					       lvm->map[le + st * len].pe);
 | 
			
		||||
 | 
			
		||||
		list_add(&lvm->lv->segments, &seg->list);
 | 
			
		||||
 | 
			
		||||
		le += seg->len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
 
 | 
			
		||||
@@ -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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -132,7 +132,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"
 | 
			
		||||
@@ -81,6 +83,8 @@ 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);
 | 
			
		||||
 | 
			
		||||
@@ -107,10 +111,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);
 | 
			
		||||
	}
 | 
			
		||||
@@ -177,6 +183,13 @@ int import_pool_pv(const struct format_type *fmt, struct pool *mem,
 | 
			
		||||
	pv->pe_alloc_count = pv->pe_count;
 | 
			
		||||
 | 
			
		||||
	list_init(&pv->tags);
 | 
			
		||||
	list_init(&pv->segments);
 | 
			
		||||
	list_init(&pv->free_segments);
 | 
			
		||||
 | 
			
		||||
	if (!alloc_pv_segment_whole_pv(mem, pv)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -199,40 +212,41 @@ 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)) {
 | 
			
		||||
		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,
 | 
			
		||||
	if (!(segtype = get_segtype_from_string(lv->vg->cmd,
 | 
			
		||||
						     "striped"))) {
 | 
			
		||||
		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;
 | 
			
		||||
 | 
			
		||||
		seg->area[j].type = AREA_PV;
 | 
			
		||||
		seg->area[j].u.pv.pv = usp->devs[j].pv;
 | 
			
		||||
		seg->area[j].u.pv.pe = 0;
 | 
			
		||||
	if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur, 
 | 
			
		||||
				     area_len * usp->num_devs, 0,
 | 
			
		||||
				     usp->striping, usp->num_devs, area_len,
 | 
			
		||||
				     0, 0))) {
 | 
			
		||||
		log_error("Unable to allocate striped lv_segment structure");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (j = 0; j < usp->num_devs; j++)
 | 
			
		||||
		set_lv_segment_area_pv(seg, j, usp->devs[j].pv, 0);
 | 
			
		||||
 | 
			
		||||
	/* add the subpool type to the segment tag list */
 | 
			
		||||
	str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
 | 
			
		||||
 | 
			
		||||
	list_add(&lv->segments, &seg->list);
 | 
			
		||||
 | 
			
		||||
	*le_cur += seg->len;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -241,37 +255,35 @@ 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,
 | 
			
		||||
					     1, area_len, POOL_PE_SIZE, 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;
 | 
			
		||||
		set_lv_segment_area_pv(seg, 0, usp->devs[j].pv, 0);
 | 
			
		||||
		list_add(&lv->segments, &seg->list);
 | 
			
		||||
 | 
			
		||||
		*le_cur += seg->len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -287,8 +299,11 @@ int import_pool_segments(struct list *lvs, struct pool *mem,
 | 
			
		||||
 | 
			
		||||
	list_iterate(lvhs, lvs) {
 | 
			
		||||
		lvl = list_item(lvhs, struct lv_list);
 | 
			
		||||
 | 
			
		||||
		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)) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -132,7 +132,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;
 | 
			
		||||
@@ -240,7 +241,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];
 | 
			
		||||
@@ -285,7 +286,7 @@ int archive_vg(struct volume_group *vg,
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -477,87 +477,6 @@ static int _count_segments(struct logical_volume *lv)
 | 
			
		||||
	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);
 | 
			
		||||
	_inc_indent(f);
 | 
			
		||||
 | 
			
		||||
	if (!id_write_format(&snap->id, 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))) {
 | 
			
		||||
		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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	seg.le = 0;
 | 
			
		||||
	seg.len = snap->origin->le_count;
 | 
			
		||||
	seg.origin = snap->origin;
 | 
			
		||||
	seg.cow = snap->cow;
 | 
			
		||||
	seg.chunk_size = snap->chunk_size;
 | 
			
		||||
 | 
			
		||||
	/* 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;
 | 
			
		||||
 | 
			
		||||
	/* 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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_dec_indent(f);
 | 
			
		||||
	outf(f, "}");
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
@@ -629,11 +548,6 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
 | 
			
		||||
		outf(f, "}");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_print_snapshots(f, vg)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_dec_indent(f);
 | 
			
		||||
	outf(f, "}");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -54,6 +54,7 @@ static struct flag _lv_flags[] = {
 | 
			
		||||
	{LOCKED, "LOCKED"},
 | 
			
		||||
	{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;
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
 | 
			
		||||
	    (isspace(vgnamebuf[len]) || vgnamebuf[len] == '{')) {
 | 
			
		||||
		return rlocn;
 | 
			
		||||
	}
 | 
			
		||||
		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,
 | 
			
		||||
@@ -341,18 +372,8 @@ 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)))) {
 | 
			
		||||
		log_error("VG %s metadata writing failed", vg->name);
 | 
			
		||||
@@ -417,8 +438,10 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
 | 
			
		||||
	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;
 | 
			
		||||
@@ -445,18 +468,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,12 +494,25 @@ 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)
 | 
			
		||||
@@ -517,7 +558,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 +584,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 +603,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 +620,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)
 | 
			
		||||
{
 | 
			
		||||
@@ -850,7 +900,7 @@ static int _scan_raw(const struct format_type *fmt)
 | 
			
		||||
		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);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -1099,34 +1149,6 @@ 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;
 | 
			
		||||
@@ -1175,18 +1197,18 @@ 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,
 | 
			
		||||
		    get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
 | 
			
		||||
					 info->dev->pvid, pv)) {
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
@@ -1272,6 +1294,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 +1309,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
 | 
			
		||||
};
 | 
			
		||||
@@ -1643,7 +1668,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");
 | 
			
		||||
 
 | 
			
		||||
@@ -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,8 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_init(&pv->tags);
 | 
			
		||||
	list_init(&pv->segments);
 | 
			
		||||
	list_init(&pv->free_segments);
 | 
			
		||||
 | 
			
		||||
	/* Optional tags */
 | 
			
		||||
	if ((cn = find_config_node(pvn, "tags")) &&
 | 
			
		||||
@@ -208,6 +211,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);
 | 
			
		||||
 | 
			
		||||
@@ -283,19 +291,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, area_count,
 | 
			
		||||
				     extent_count, 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;
 | 
			
		||||
@@ -361,19 +363,14 @@ 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;
 | 
			
		||||
			set_lv_segment_area_pv(seg, s, pv, cv->next->v.i);
 | 
			
		||||
			/*
 | 
			
		||||
			 * 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);
 | 
			
		||||
		} else {
 | 
			
		||||
			log_error("Couldn't find volume '%s' "
 | 
			
		||||
				  "for segment '%s'.",
 | 
			
		||||
@@ -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,8 +560,16 @@ 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)) {
 | 
			
		||||
	/*
 | 
			
		||||
	 * 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)) {
 | 
			
		||||
@@ -570,16 +577,13 @@ static int _read_lvsegs(struct format_instance *fid, struct pool *mem,
 | 
			
		||||
			  "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 {
 | 
			
		||||
		vg->lv_count--;
 | 
			
		||||
		list_del(&lvl->list);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -117,12 +117,17 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
 | 
			
		||||
	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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -182,10 +187,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;
 | 
			
		||||
 | 
			
		||||
@@ -279,7 +287,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 +317,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,12 +147,18 @@ static int _send_request(char *inbuf, int inlen, char **retbuf)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Was it an error ? */
 | 
			
		||||
	if (outheader->status < 0) {
 | 
			
		||||
		errno = -outheader->status;
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
@@ -321,3 +324,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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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] = "  ";
 | 
			
		||||
@@ -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,23 @@
 | 
			
		||||
#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,
 | 
			
		||||
				    uint32_t area_count,
 | 
			
		||||
				    uint32_t area_len,
 | 
			
		||||
				    uint32_t chunk_size,
 | 
			
		||||
				    uint32_t extents_copied);
 | 
			
		||||
 | 
			
		||||
struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
 | 
			
		||||
				      uint32_t allocated);
 | 
			
		||||
 | 
			
		||||
void 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);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -61,22 +61,57 @@ static void _put_extents(struct lv_segment *seg)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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,
 | 
			
		||||
				    uint32_t area_count,
 | 
			
		||||
				    uint32_t area_len,
 | 
			
		||||
				    uint32_t chunk_size,
 | 
			
		||||
				    uint32_t extents_copied)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
	uint32_t len = sizeof(*seg) + (num_areas * sizeof(seg->area[0]));
 | 
			
		||||
	uint32_t sz = sizeof(*seg) + (area_count * sizeof(seg->area[0]));
 | 
			
		||||
 | 
			
		||||
	if (!(seg = pool_zalloc(mem, len))) {
 | 
			
		||||
	if (!(seg = pool_zalloc(mem, sz))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	seg->area_count = num_areas;
 | 
			
		||||
	seg->segtype = segtype;
 | 
			
		||||
	seg->lv = lv;
 | 
			
		||||
	seg->le = le;
 | 
			
		||||
	seg->len = len;
 | 
			
		||||
	seg->status = status;
 | 
			
		||||
	seg->stripe_size = stripe_size;
 | 
			
		||||
	seg->area_count = area_count;
 | 
			
		||||
	seg->area_len = area_len;
 | 
			
		||||
	seg->chunk_size = chunk_size;
 | 
			
		||||
	seg->extents_copied = extents_copied;
 | 
			
		||||
	list_init(&seg->tags);
 | 
			
		||||
 | 
			
		||||
	return seg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
 | 
			
		||||
			    struct physical_volume *pv, uint32_t pe)
 | 
			
		||||
{
 | 
			
		||||
	seg->area[area_num].type = AREA_PV;
 | 
			
		||||
	seg->area[area_num].u.pv.pv = pv;
 | 
			
		||||
	seg->area[area_num].u.pv.pe = pe;
 | 
			
		||||
	seg->area[area_num].u.pv.pvseg = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
 | 
			
		||||
			    struct logical_volume *lv, uint32_t le)
 | 
			
		||||
{
 | 
			
		||||
	seg->area[area_num].type = AREA_LV;
 | 
			
		||||
	seg->area[area_num].u.lv.lv = lv;
 | 
			
		||||
	seg->area[area_num].u.lv.le = le;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
 | 
			
		||||
				uint32_t stripe_size,
 | 
			
		||||
				struct segment_type *segtype,
 | 
			
		||||
@@ -98,24 +133,17 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
 | 
			
		||||
	if (smallest < area_len)
 | 
			
		||||
		area_len = smallest;
 | 
			
		||||
 | 
			
		||||
	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, area_count))) {
 | 
			
		||||
		log_err("Couldn't allocate new parallel segment.");
 | 
			
		||||
	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, *ix,
 | 
			
		||||
				     area_len * (striped ? area_count : 1),
 | 
			
		||||
				     0u, stripe_size, area_count, area_len,
 | 
			
		||||
				     0u, 0u))) {
 | 
			
		||||
		log_error("Couldn't allocate new parallel segment.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	seg->lv = lv;
 | 
			
		||||
	seg->segtype = segtype;
 | 
			
		||||
	seg->le = *ix;
 | 
			
		||||
	seg->len = area_len * (striped ? area_count : 1);
 | 
			
		||||
	seg->area_len = area_len;
 | 
			
		||||
	seg->stripe_size = stripe_size;
 | 
			
		||||
	seg->extents_copied = 0u;
 | 
			
		||||
 | 
			
		||||
	for (s = 0; s < area_count; s++) {
 | 
			
		||||
		struct pv_area *pva = areas[s];
 | 
			
		||||
		seg->area[s].type = AREA_PV;
 | 
			
		||||
		seg->area[s].u.pv.pv = pva->map->pvl->pv;
 | 
			
		||||
		seg->area[s].u.pv.pe = pva->start;
 | 
			
		||||
		set_lv_segment_area_pv(seg, s, pva->map->pvl->pv, pva->start);
 | 
			
		||||
		consume_pv_area(pva, area_len);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -221,34 +249,31 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix,
 | 
			
		||||
{
 | 
			
		||||
	uint32_t count, remaining;
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
	struct segment_type *segtype;
 | 
			
		||||
 | 
			
		||||
	count = pva->count;
 | 
			
		||||
	remaining = lv->le_count - *ix;
 | 
			
		||||
	if (count > remaining)
 | 
			
		||||
		count = remaining;
 | 
			
		||||
 | 
			
		||||
	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 1))) {
 | 
			
		||||
		log_err("Couldn't allocate new stripe segment.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	seg->lv = lv;
 | 
			
		||||
	if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) {
 | 
			
		||||
	if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	seg->le = *ix;
 | 
			
		||||
	seg->len = count;
 | 
			
		||||
	seg->area_len = count;
 | 
			
		||||
	seg->stripe_size = 0;
 | 
			
		||||
	seg->area[0].type = AREA_PV;
 | 
			
		||||
	seg->area[0].u.pv.pv = map->pvl->pv;
 | 
			
		||||
	seg->area[0].u.pv.pe = pva->start;
 | 
			
		||||
 | 
			
		||||
	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, *ix,
 | 
			
		||||
				     count, 0, 0, 1, count, 0, 0))) {
 | 
			
		||||
		log_error("Couldn't allocate new stripe segment.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	set_lv_segment_area_pv(seg, 0, map->pvl->pv, pva->start);
 | 
			
		||||
 | 
			
		||||
	list_add(&lv->segments, &seg->list);
 | 
			
		||||
 | 
			
		||||
	consume_pv_area(pva, count);
 | 
			
		||||
	*ix += count;
 | 
			
		||||
	consume_pv_area(pva, seg->len);
 | 
			
		||||
	*ix += seg->len;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -266,30 +291,21 @@ static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix,
 | 
			
		||||
	if (count > remaining)
 | 
			
		||||
		count = remaining;
 | 
			
		||||
 | 
			
		||||
	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 2))) {
 | 
			
		||||
	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, *ix,
 | 
			
		||||
				     count, 0, 0, 2, count, 0, 0))) {
 | 
			
		||||
		log_err("Couldn't allocate new mirrored segment.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	seg->lv = lv;
 | 
			
		||||
	seg->segtype = segtype;
 | 
			
		||||
	seg->le = *ix;
 | 
			
		||||
	seg->status = 0u;
 | 
			
		||||
	seg->len = count;
 | 
			
		||||
	seg->area_len = count;
 | 
			
		||||
	seg->stripe_size = 0;
 | 
			
		||||
	seg->extents_copied = 0u;
 | 
			
		||||
	/* FIXME Remove AREA_PV restriction here? */
 | 
			
		||||
	seg->area[0].type = AREA_PV;
 | 
			
		||||
	seg->area[0].u.pv.pv = mirrored_pv;
 | 
			
		||||
	seg->area[0].u.pv.pe = mirrored_pe;
 | 
			
		||||
	seg->area[1].type = AREA_PV;
 | 
			
		||||
	seg->area[1].u.pv.pv = map->pvl->pv;
 | 
			
		||||
	seg->area[1].u.pv.pe = pva->start;
 | 
			
		||||
	set_lv_segment_area_pv(seg, 0, mirrored_pv, mirrored_pe);
 | 
			
		||||
	set_lv_segment_area_pv(seg, 1, map->pvl->pv, pva->start);
 | 
			
		||||
 | 
			
		||||
	list_add(&lv->segments, &seg->list);
 | 
			
		||||
 | 
			
		||||
	consume_pv_area(pva, count);
 | 
			
		||||
	*ix += count;
 | 
			
		||||
	consume_pv_area(pva, seg->len);
 | 
			
		||||
	*ix += seg->len;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -421,25 +437,44 @@ static int _alloc_virtual(struct logical_volume *lv,
 | 
			
		||||
{
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
 | 
			
		||||
	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 0))) {
 | 
			
		||||
		log_err("Couldn't allocate new zero segment.");
 | 
			
		||||
	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, allocated,
 | 
			
		||||
				     lv->le_count - allocated, 0, 0, 0,
 | 
			
		||||
				     lv->le_count - allocated, 0, 0))) {
 | 
			
		||||
		log_error("Couldn't allocate new zero segment.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	seg->lv = lv;
 | 
			
		||||
	seg->segtype = segtype;
 | 
			
		||||
	seg->status = 0u;
 | 
			
		||||
	seg->le = allocated;
 | 
			
		||||
	seg->len = lv->le_count - allocated;
 | 
			
		||||
	seg->area_len = seg->len;
 | 
			
		||||
	seg->stripe_size = 0;
 | 
			
		||||
	seg->extents_copied = 0u;
 | 
			
		||||
	list_add(&lv->segments, &seg->list);
 | 
			
		||||
	lv->status |= VIRTUAL;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
 | 
			
		||||
				      uint32_t allocated)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
	struct segment_type *segtype;
 | 
			
		||||
 | 
			
		||||
	segtype = get_segtype_from_string(lv->vg->cmd, "snapshot");
 | 
			
		||||
	if (!segtype) {
 | 
			
		||||
		log_error("Failed to find snapshot segtype");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, allocated,
 | 
			
		||||
				     lv->le_count - allocated, 0, 0, 0,
 | 
			
		||||
				     lv->le_count - allocated, 0, 0))) {
 | 
			
		||||
		log_error("Couldn't allocate new snapshot segment.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_add(&lv->segments, &seg->list);
 | 
			
		||||
	lv->status |= VIRTUAL;
 | 
			
		||||
 | 
			
		||||
	return seg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Chooses a correct allocation policy.
 | 
			
		||||
 */
 | 
			
		||||
@@ -543,8 +578,10 @@ static char *_generate_lv_name(struct volume_group *vg, const char *format,
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
	struct cmd_context *cmd = vg->cmd;
 | 
			
		||||
@@ -565,6 +602,7 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!import)
 | 
			
		||||
		log_verbose("Creating logical volume %s", name);
 | 
			
		||||
 | 
			
		||||
	if (!(ll = pool_zalloc(cmd->mem, sizeof(*ll))) ||
 | 
			
		||||
@@ -592,9 +630,14 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
 | 
			
		||||
	lv->minor = -1;
 | 
			
		||||
	lv->size = UINT64_C(0);
 | 
			
		||||
	lv->le_count = 0;
 | 
			
		||||
	lv->snapshot = NULL;
 | 
			
		||||
	list_init(&lv->snapshot_segs);
 | 
			
		||||
	list_init(&lv->segments);
 | 
			
		||||
	list_init(&lv->tags);
 | 
			
		||||
 | 
			
		||||
	if (lvid)
 | 
			
		||||
		lv->lvid = *lvid;
 | 
			
		||||
 | 
			
		||||
	if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		if (ll)
 | 
			
		||||
@@ -602,7 +645,9 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!import)
 | 
			
		||||
		vg->lv_count++;
 | 
			
		||||
 | 
			
		||||
	list_add(&vg->lvs, &ll->list);
 | 
			
		||||
 | 
			
		||||
	return lv;
 | 
			
		||||
 
 | 
			
		||||
@@ -98,11 +98,17 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* 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->area_count, seg->area_len,
 | 
			
		||||
					   seg->chunk_size,
 | 
			
		||||
					   seg->extents_copied))) {
 | 
			
		||||
		log_error("Couldn't allocate cloned LV segment.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* FIXME Avoid the memcpy */
 | 
			
		||||
	len = sizeof(*seg) + (seg->area_count * sizeof(seg->area[0]));
 | 
			
		||||
	memcpy(split_seg, seg, len);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
@@ -109,6 +111,57 @@ 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_to->free_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 list *pvh;
 | 
			
		||||
	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(pvh, &vg->pvs) {
 | 
			
		||||
		pvl = list_item(pvh, struct pv_list);
 | 
			
		||||
		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)
 | 
			
		||||
{
 | 
			
		||||
@@ -221,7 +274,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 +301,153 @@ 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;
 | 
			
		||||
	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 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->area[s].type) {
 | 
			
		||||
				case AREA_PV:
 | 
			
		||||
					if (!_recalc_extents
 | 
			
		||||
					    (&seg->area[s].u.pv.pe, lv->name,
 | 
			
		||||
					     " area start", old_size,
 | 
			
		||||
					     new_size)) {
 | 
			
		||||
						stack;
 | 
			
		||||
						return 0;
 | 
			
		||||
					}
 | 
			
		||||
					break;
 | 
			
		||||
				case AREA_LV:
 | 
			
		||||
					if (!_recalc_extents
 | 
			
		||||
					    (&seg->area[s].u.lv.le, lv->name,
 | 
			
		||||
					     " area start", old_size,
 | 
			
		||||
					     new_size)) {
 | 
			
		||||
						stack;
 | 
			
		||||
						return 0;
 | 
			
		||||
					}
 | 
			
		||||
					break;
 | 
			
		||||
				default:
 | 
			
		||||
					log_error("Unrecognised segment type "
 | 
			
		||||
						  "%u", seg->area[s].type);
 | 
			
		||||
					return 0;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Sizes in sectors */
 | 
			
		||||
struct physical_volume *pv_create(const struct format_type *fmt,
 | 
			
		||||
				  struct device *dev,
 | 
			
		||||
@@ -267,10 +466,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 +510,8 @@ struct physical_volume *pv_create(const struct format_type *fmt,
 | 
			
		||||
	pv->fmt = fmt;
 | 
			
		||||
 | 
			
		||||
	list_init(&pv->tags);
 | 
			
		||||
	list_init(&pv->segments);
 | 
			
		||||
	list_init(&pv->free_segments);
 | 
			
		||||
 | 
			
		||||
	if (!fmt->ops->pv_setup(fmt, pe_start, existing_extent_count,
 | 
			
		||||
				existing_extent_size,
 | 
			
		||||
@@ -504,6 +708,7 @@ int vg_write(struct volume_group *vg)
 | 
			
		||||
			/* Revert */
 | 
			
		||||
			list_uniterate(mdah2, &vg->fid->metadata_areas, mdah) {
 | 
			
		||||
				mda = list_item(mdah2, struct metadata_area);
 | 
			
		||||
 | 
			
		||||
				if (mda->ops->vg_revert &&
 | 
			
		||||
				    !mda->ops->vg_revert(vg->fid, vg, mda)) {
 | 
			
		||||
					stack;
 | 
			
		||||
@@ -525,6 +730,24 @@ int vg_write(struct volume_group *vg)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Now pre-commit each copy of the new metadata */
 | 
			
		||||
	list_iterate(mdah, &vg->fid->metadata_areas) {
 | 
			
		||||
		mda = list_item(mdah, struct metadata_area);
 | 
			
		||||
		if (mda->ops->vg_precommit &&
 | 
			
		||||
		    !mda->ops->vg_precommit(vg->fid, vg, mda)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			/* Revert */
 | 
			
		||||
			list_iterate(mdah2, &vg->fid->metadata_areas) {
 | 
			
		||||
				mda = list_item(mdah2, struct metadata_area);
 | 
			
		||||
				if (mda->ops->vg_revert &&
 | 
			
		||||
				    !mda->ops->vg_revert(vg->fid, vg, mda)) {
 | 
			
		||||
					stack;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -595,7 +818,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))) {
 | 
			
		||||
@@ -627,8 +849,9 @@ 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;
 | 
			
		||||
@@ -638,6 +861,11 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
 | 
			
		||||
	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 +879,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 +887,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");
 | 
			
		||||
@@ -668,7 +902,10 @@ 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))) {
 | 
			
		||||
		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 +921,67 @@ 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) {
 | 
			
		||||
		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(mdah, &fid->metadata_areas) {
 | 
			
		||||
			mda = list_item(mdah, struct metadata_area);
 | 
			
		||||
			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;
 | 
			
		||||
 | 
			
		||||
@@ -711,6 +1000,11 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
 | 
			
		||||
			log_error("Automatic metadata correction failed");
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		if (!vg_commit(correct_vg)) {
 | 
			
		||||
			log_error("Automatic metadata correction commit "
 | 
			
		||||
				  "failed");
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
 | 
			
		||||
@@ -725,6 +1019,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.
 | 
			
		||||
@@ -760,7 +1067,7 @@ 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;
 | 
			
		||||
	}
 | 
			
		||||
@@ -824,14 +1131,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;
 | 
			
		||||
@@ -840,21 +1147,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);
 | 
			
		||||
	list_init(&pv->free_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
 | 
			
		||||
	
 | 
			
		||||
	if (!alloc_pv_segment_whole_pv(cmd->mem, pv)) {
 | 
			
		||||
		stack;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return pv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@
 | 
			
		||||
#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 */
 | 
			
		||||
@@ -68,6 +68,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 +99,20 @@ 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 list freelist;	/* Member of pv->free_segments */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct physical_volume {
 | 
			
		||||
	struct id id;
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
@@ -113,6 +128,8 @@ struct physical_volume {
 | 
			
		||||
	uint32_t pe_count;
 | 
			
		||||
	uint32_t pe_alloc_count;
 | 
			
		||||
 | 
			
		||||
	struct list segments;	/* Ordered pv_segments covering complete PV */
 | 
			
		||||
	struct list free_segments;	/* Free pv_segments for this PV */
 | 
			
		||||
	struct list tags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -124,6 +141,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 +160,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 +207,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,7 +230,8 @@ 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;	/* In sectors */
 | 
			
		||||
	uint32_t extents_copied;
 | 
			
		||||
 | 
			
		||||
	struct list tags;
 | 
			
		||||
@@ -222,6 +243,7 @@ struct lv_segment {
 | 
			
		||||
			struct {
 | 
			
		||||
				struct physical_volume *pv;
 | 
			
		||||
				uint32_t pe;
 | 
			
		||||
				struct pv_segment *pvseg;
 | 
			
		||||
			} pv;
 | 
			
		||||
			struct {
 | 
			
		||||
				struct logical_volume *lv;
 | 
			
		||||
@@ -246,20 +268,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 +299,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 +388,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,13 +424,17 @@ 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,
 | 
			
		||||
@@ -439,6 +461,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);
 | 
			
		||||
@@ -492,13 +516,12 @@ 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 volume_group *vg, struct logical_volume *cow);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@
 | 
			
		||||
#include "segtype.h"
 | 
			
		||||
#include "display.h"
 | 
			
		||||
#include "activate.h"
 | 
			
		||||
#include "lv_alloc.h"
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * Replace any LV segments on given PV with temporary mirror.
 | 
			
		||||
@@ -153,9 +154,7 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
 | 
			
		||||
						  "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);
 | 
			
		||||
	
 | 
			
		||||
				extent_count += seg->area_len;
 | 
			
		||||
	
 | 
			
		||||
@@ -225,9 +224,9 @@ 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;
 | 
			
		||||
				set_lv_segment_area_pv(seg, s,
 | 
			
		||||
						       mir_seg->area[c].u.pv.pv,
 | 
			
		||||
						       mir_seg->area[c].u.pv.pe);
 | 
			
		||||
 | 
			
		||||
				/* Replace mirror with old area */
 | 
			
		||||
				if (!
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								lib/metadata/pv_alloc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								lib/metadata/pv_alloc.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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_free_new,
 | 
			
		||||
	    struct list *peg_old);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										83
									
								
								lib/metadata/pv_manip.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								lib/metadata/pv_manip.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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"
 | 
			
		||||
 | 
			
		||||
static struct pv_segment *_alloc_pv_segment(struct pool *mem,
 | 
			
		||||
					    struct physical_volume *pv,
 | 
			
		||||
					    uint32_t pe, uint32_t len)
 | 
			
		||||
{
 | 
			
		||||
	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 = NULL;
 | 
			
		||||
	peg->lv_area = 0;
 | 
			
		||||
 | 
			
		||||
	list_init(&peg->list);
 | 
			
		||||
	list_init(&peg->freelist);
 | 
			
		||||
 | 
			
		||||
	return peg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int alloc_pv_segment_whole_pv(struct pool *mem, struct physical_volume *pv)
 | 
			
		||||
{
 | 
			
		||||
        struct pv_segment *peg;
 | 
			
		||||
 | 
			
		||||
	/* FIXME Cope with holes in PVs */
 | 
			
		||||
        if (!(peg = _alloc_pv_segment(mem, pv, 0, pv->pe_count))) {
 | 
			
		||||
                stack;
 | 
			
		||||
                return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        list_add(&pv->segments, &peg->list);
 | 
			
		||||
        list_add(&pv->free_segments, &peg->freelist);
 | 
			
		||||
 | 
			
		||||
        return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int peg_dup(struct pool *mem, struct list *peg_new, struct list *peg_free_new,
 | 
			
		||||
	    struct list *peg_old)
 | 
			
		||||
{
 | 
			
		||||
	struct pv_segment *peg, *pego;
 | 
			
		||||
 | 
			
		||||
	list_init(peg_new);
 | 
			
		||||
	list_init(peg_free_new);
 | 
			
		||||
 | 
			
		||||
	list_iterate_items(pego, peg_old) {
 | 
			
		||||
		if (!(peg = _alloc_pv_segment(mem, pego->pv, pego->pe,
 | 
			
		||||
					      pego->len))) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return 0;
 | 
			
		||||
		} 
 | 
			
		||||
		peg->lvseg = pego->lvseg;
 | 
			
		||||
		peg->lv_area = pego->lv_area;
 | 
			
		||||
		list_add(peg_new, &peg->list);
 | 
			
		||||
		if (!peg->lvseg)
 | 
			
		||||
			list_add(peg_free_new, &peg->freelist);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -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 lv->snapshot ? 1 : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	return 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 lv->snapshot;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 ? NULL : "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))) {
 | 
			
		||||
		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)
 | 
			
		||||
{
 | 
			
		||||
	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;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* fail */
 | 
			
		||||
	log_err("Asked to remove an unknown snapshot.");
 | 
			
		||||
	if (!lv_remove(vg, cow->snapshot->lv)) {
 | 
			
		||||
		log_error("Failed to remove internal snapshot LV %s",
 | 
			
		||||
			  cow->snapshot->lv->name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cow->snapshot = NULL;
 | 
			
		||||
 | 
			
		||||
	vg->snapshot_count--;
 | 
			
		||||
	vg->lv_count++;
 | 
			
		||||
	cow->status |= VISIBLE_LV;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -131,6 +131,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);
 | 
			
		||||
@@ -166,10 +167,10 @@ static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
 | 
			
		||||
				    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);
 | 
			
		||||
 
 | 
			
		||||
@@ -48,13 +48,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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -190,7 +191,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 +221,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;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -71,4 +71,7 @@ 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;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -295,7 +296,7 @@ static int _lvkmaj_disp(struct report_handle *rh, struct field *field,
 | 
			
		||||
	struct lvinfo info;
 | 
			
		||||
	uint64_t minusone = UINT64_C(-1);
 | 
			
		||||
 | 
			
		||||
	if (lv_info(lv, &info) && info.exists)
 | 
			
		||||
	if (lv_info(lv, &info, 0) && info.exists)
 | 
			
		||||
		return _int_disp(rh, field, &info.major);
 | 
			
		||||
	else
 | 
			
		||||
		return _int_disp(rh, field, &minusone);
 | 
			
		||||
@@ -310,7 +311,7 @@ static int _lvkmin_disp(struct report_handle *rh, struct field *field,
 | 
			
		||||
	struct lvinfo info;
 | 
			
		||||
	uint64_t minusone = UINT64_C(-1);
 | 
			
		||||
 | 
			
		||||
	if (lv_info(lv, &info) && info.exists)
 | 
			
		||||
	if (lv_info(lv, &info, 0) && info.exists)
 | 
			
		||||
		return _int_disp(rh, field, &info.minor);
 | 
			
		||||
	else
 | 
			
		||||
		return _int_disp(rh, field, &minusone);
 | 
			
		||||
@@ -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))) {
 | 
			
		||||
@@ -362,7 +363,7 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field,
 | 
			
		||||
	else
 | 
			
		||||
		repstr[3] = '-';
 | 
			
		||||
 | 
			
		||||
	if (lv_info(lv, &info) && info.exists) {
 | 
			
		||||
	if (lv_info(lv, &info, 1) && info.exists) {
 | 
			
		||||
		if (info.suspended)
 | 
			
		||||
			repstr[4] = 's';	/* Suspended */
 | 
			
		||||
		else
 | 
			
		||||
@@ -373,8 +374,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 +479,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;
 | 
			
		||||
@@ -573,7 +574,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 +585,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 +596,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 +611,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 +626,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 +641,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 +664,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 +763,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 +774,16 @@ static int _snpercent_disp(struct report_handle *rh, struct field *field,
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(snap = find_cow(lv)) ||
 | 
			
		||||
	    (lv_info(snap->cow, &info) && !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 +857,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;
 | 
			
		||||
@@ -1077,6 +1079,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 +1101,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 +1113,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,7 +1135,7 @@ 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;
 | 
			
		||||
@@ -1186,6 +1195,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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,9 +29,7 @@ static unsigned char _inverse_c[256];
 | 
			
		||||
int lvid_create(union lvid *lvid, struct id *vgid)
 | 
			
		||||
{
 | 
			
		||||
	memcpy(lvid->id, vgid, sizeof(*lvid->id));
 | 
			
		||||
	id_create(&lvid->id[1]);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
	return id_create(&lvid->id[1]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void uuid_from_num(char *uuid, uint32_t num)
 | 
			
		||||
@@ -83,16 +81,18 @@ int id_create(struct id *id)
 | 
			
		||||
 | 
			
		||||
	memset(id->uuid, 0, len);
 | 
			
		||||
	if ((randomfile = open("/dev/urandom", O_RDONLY)) < 0) {
 | 
			
		||||
		log_sys_error("open", "id_create");
 | 
			
		||||
		log_sys_error("open", "id_create: /dev/urandom");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (read(randomfile, id->uuid, len) != len) {
 | 
			
		||||
		log_sys_error("read", "id_create");
 | 
			
		||||
		close(randomfile);
 | 
			
		||||
		log_sys_error("read", "id_create: /dev/urandom");
 | 
			
		||||
		if (close(randomfile))
 | 
			
		||||
			stack;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	close(randomfile);
 | 
			
		||||
	if (close(randomfile))
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * Skip out the last 2 chars in randomized creation for LVM1
 | 
			
		||||
 
 | 
			
		||||
@@ -25,11 +25,11 @@ struct id {
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Unique logical volume identifier
 | 
			
		||||
 * With format1 this is VG uuid + LV uuid + '\0'
 | 
			
		||||
 * With format1 this is VG uuid + LV uuid + '\0' + padding
 | 
			
		||||
 */
 | 
			
		||||
union lvid {
 | 
			
		||||
	struct id id[2];
 | 
			
		||||
	char s[2 * sizeof(struct id) + 1];
 | 
			
		||||
	char s[2 * sizeof(struct id) + 1 + 7];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int lvid_from_lvnum(union lvid *lvid, struct id *vgid, uint32_t lv_num);
 | 
			
		||||
 
 | 
			
		||||
@@ -17,12 +17,25 @@ top_srcdir = @top_srcdir@
 | 
			
		||||
VPATH = @srcdir@
 | 
			
		||||
interface = @interface@
 | 
			
		||||
 | 
			
		||||
ifeq ("@DMEVENTD@", "yes")
 | 
			
		||||
   SUBDIRS += event
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ($(MAKECMDGOALS),distclean)
 | 
			
		||||
  SUBDIRS += event
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
SOURCES = libdm-common.c libdm-file.c $(interface)/libdm-iface.c
 | 
			
		||||
 | 
			
		||||
INCLUDES = -I$(interface)
 | 
			
		||||
 | 
			
		||||
LIB_STATIC = $(interface)/libdevmapper.a
 | 
			
		||||
 | 
			
		||||
ifeq ("@LIB_SUFFIX@","dylib")
 | 
			
		||||
  LIB_SHARED = $(interface)/libdevmapper.dylib
 | 
			
		||||
else
 | 
			
		||||
  LIB_SHARED = $(interface)/libdevmapper.so
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
CFLAGS += -DDEVICE_UID=@DEVICE_UID@ -DDEVICE_GID=@DEVICE_GID@ \
 | 
			
		||||
	  -DDEVICE_MODE=@DEVICE_MODE@
 | 
			
		||||
@@ -41,7 +54,8 @@ endif
 | 
			
		||||
install: $(INSTALL_TYPE)
 | 
			
		||||
 | 
			
		||||
install_dynamic: install_@interface@
 | 
			
		||||
	$(LN_S) -f libdevmapper.so.$(LIB_VERSION) $(libdir)/libdevmapper.so
 | 
			
		||||
	$(LN_S) -f libdevmapper.$(LIB_SUFFIX).$(LIB_VERSION) \
 | 
			
		||||
		$(libdir)/libdevmapper.$(LIB_SUFFIX)
 | 
			
		||||
	$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper.h \
 | 
			
		||||
		$(includedir)/libdevmapper.h
 | 
			
		||||
 | 
			
		||||
@@ -50,13 +64,13 @@ install_static: install_@interface@_static
 | 
			
		||||
	$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper.h \
 | 
			
		||||
		$(includedir)/libdevmapper.h
 | 
			
		||||
 | 
			
		||||
install_fs: fs/libdevmapper.so
 | 
			
		||||
install_fs: fs/libdevmapper.$(LIB_SUFFIX)
 | 
			
		||||
	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
 | 
			
		||||
		$(libdir)/libdevmapper.so.$(LIB_VERSION)
 | 
			
		||||
		$(libdir)/libdevmapper.$(LIB_SUFFIX).$(LIB_VERSION)
 | 
			
		||||
 | 
			
		||||
install_ioctl: ioctl/libdevmapper.so
 | 
			
		||||
install_ioctl: ioctl/libdevmapper.$(LIB_SUFFIX)
 | 
			
		||||
	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
 | 
			
		||||
		$(libdir)/libdevmapper.so.$(LIB_VERSION)
 | 
			
		||||
		$(libdir)/libdevmapper.$(LIB_SUFFIX).$(LIB_VERSION)
 | 
			
		||||
 | 
			
		||||
install_ioctl_static: ioctl/libdevmapper.a
 | 
			
		||||
	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
 | 
			
		||||
 
 | 
			
		||||
@@ -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,127 @@ 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 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)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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;
 | 
			
		||||
 
 | 
			
		||||
@@ -30,13 +30,14 @@
 | 
			
		||||
#ifdef linux
 | 
			
		||||
#  include "kdev_t.h"
 | 
			
		||||
#  include <linux/limits.h>
 | 
			
		||||
#  include <linux/dm-ioctl.h>
 | 
			
		||||
#else
 | 
			
		||||
#  define MAJOR(x) major((x))
 | 
			
		||||
#  define MINOR(x) minor((x))
 | 
			
		||||
#  define MKDEV(x,y) makedev((x),(y))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <linux/dm-ioctl.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Ensure build compatibility.  
 | 
			
		||||
 * The hard-coded versions here are the highest present 
 | 
			
		||||
@@ -228,6 +229,7 @@ static int _create_control(const char *control, uint32_t major, uint32_t minor)
 | 
			
		||||
 | 
			
		||||
static int _open_control(void)
 | 
			
		||||
{
 | 
			
		||||
#ifdef DM_IOCTLS
 | 
			
		||||
	char control[PATH_MAX];
 | 
			
		||||
	uint32_t major = 0, minor;
 | 
			
		||||
 | 
			
		||||
@@ -253,6 +255,9 @@ static int _open_control(void)
 | 
			
		||||
error:
 | 
			
		||||
	log_error("Failure to communicate with kernel device-mapper driver.");
 | 
			
		||||
	return 0;
 | 
			
		||||
#else
 | 
			
		||||
	return 1;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dm_task_destroy(struct dm_task *dmt)
 | 
			
		||||
@@ -608,7 +613,9 @@ static int _dm_task_run_v1(struct dm_task *dmt)
 | 
			
		||||
	if (dmt->type == DM_DEVICE_LIST) {
 | 
			
		||||
		if (!_dm_names_v1(dmi))
 | 
			
		||||
			goto bad;
 | 
			
		||||
	} else if (ioctl(_control_fd, command, dmi) < 0) {
 | 
			
		||||
	} 
 | 
			
		||||
#ifdef DM_IOCTLS
 | 
			
		||||
	else if (ioctl(_control_fd, command, dmi) < 0) {
 | 
			
		||||
		if (_log_suppress)
 | 
			
		||||
			log_verbose("device-mapper ioctl cmd %d failed: %s",
 | 
			
		||||
				    _IOC_NR(command), strerror(errno));
 | 
			
		||||
@@ -617,6 +624,8 @@ static int _dm_task_run_v1(struct dm_task *dmt)
 | 
			
		||||
				  _IOC_NR(command), strerror(errno));
 | 
			
		||||
		goto bad;
 | 
			
		||||
	}
 | 
			
		||||
#else /* Userspace alternative for testing */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (dmi->flags & DM_BUFFER_FULL_FLAG)
 | 
			
		||||
		/* FIXME Increase buffer size and retry operation (if query) */
 | 
			
		||||
@@ -1313,22 +1322,26 @@ int dm_task_run(struct dm_task *dmt)
 | 
			
		||||
		  dmi->name, dmi->uuid, dmt->newname ? dmt->newname : "",
 | 
			
		||||
		  dmt->no_open_count ? 'N' : 'O',
 | 
			
		||||
		  dmt->sector, dmt->message ? dmt->message : "");
 | 
			
		||||
#ifdef DM_IOCTLS
 | 
			
		||||
	if (ioctl(_control_fd, command, dmi) < 0) {
 | 
			
		||||
		if (errno == ENXIO && ((dmt->type == DM_DEVICE_INFO) ||
 | 
			
		||||
				       (dmt->type == DM_DEVICE_MKNODES))) {
 | 
			
		||||
				       (dmt->type == DM_DEVICE_MKNODES)))
 | 
			
		||||
			dmi->flags &= ~DM_EXISTS_FLAG;	/* FIXME */
 | 
			
		||||
			goto ignore_error;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			if (_log_suppress)
 | 
			
		||||
			log_verbose("device-mapper ioctl cmd %d failed: %s",
 | 
			
		||||
				log_verbose("device-mapper ioctl "
 | 
			
		||||
					    "cmd %d failed: %s",
 | 
			
		||||
					    _IOC_NR(command), strerror(errno));
 | 
			
		||||
			else
 | 
			
		||||
			log_error("device-mapper ioctl cmd %d failed: %s",
 | 
			
		||||
				log_error("device-mapper ioctl "
 | 
			
		||||
					  "cmd %d failed: %s",
 | 
			
		||||
					  _IOC_NR(command), strerror(errno));
 | 
			
		||||
			goto bad;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#else /* Userspace alternative for testing */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
      ignore_error:
 | 
			
		||||
	switch (dmt->type) {
 | 
			
		||||
	case DM_DEVICE_CREATE:
 | 
			
		||||
		add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev),
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@
 | 
			
		||||
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <sys/param.h>
 | 
			
		||||
 | 
			
		||||
#include <linux/dm-ioctl.h>
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_SELINUX
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										83
									
								
								libdm/libdm-event.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								libdm/libdm-event.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef LIB_DMEVENT_H
 | 
			
		||||
#define LIB_DMEVENT_H
 | 
			
		||||
 | 
			
		||||
#include "list.h"
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#define	DAEMON		"/sbin/dmeventd"
 | 
			
		||||
#define LOCKFILE	"/var/lock/dmeventd"
 | 
			
		||||
#define	FIFO_CLIENT	"/var/run/dmeventd-client"
 | 
			
		||||
#define	FIFO_SERVER	"/var/run/dmeventd-server"
 | 
			
		||||
#define PIDFILE		"/var/run/dmeventd.pid"
 | 
			
		||||
 | 
			
		||||
/* Commands for the daemon passed in the message below. */
 | 
			
		||||
enum dmeventd_command {
 | 
			
		||||
	CMD_ACTIVE = 1,
 | 
			
		||||
	CMD_REGISTER_FOR_EVENT,
 | 
			
		||||
	CMD_UNREGISTER_FOR_EVENT,
 | 
			
		||||
	CMD_GET_NEXT_REGISTERED_DEVICE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Message passed between client and daemon. */
 | 
			
		||||
struct daemon_message {
 | 
			
		||||
	union {
 | 
			
		||||
		unsigned int cmd;
 | 
			
		||||
		int	 status;
 | 
			
		||||
	} opcode;
 | 
			
		||||
	char msg[252];
 | 
			
		||||
} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
/* Fifos for client/daemon communication. */
 | 
			
		||||
struct fifos
 | 
			
		||||
{
 | 
			
		||||
	int client;
 | 
			
		||||
	int server;
 | 
			
		||||
	char *client_path;
 | 
			
		||||
	char *server_path;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Event type definitions. */
 | 
			
		||||
enum event_type {
 | 
			
		||||
	SINGLE		= 0x01, /* Report multiple errors just once. */
 | 
			
		||||
	MULTI		= 0x02, /* Report all of them. */
 | 
			
		||||
	SECTOR_ERROR	= 0x04, /* Failure on a particular sector. */
 | 
			
		||||
	DEVICE_ERROR	= 0x08, /* Device failure. */
 | 
			
		||||
	PATH_ERROR	= 0x10, /* Failure on an io path. */
 | 
			
		||||
	ADAPTOR_ERROR	= 0x20, /* Failure off a host adaptor. */
 | 
			
		||||
	SYNC_STATUS	= 0x40, /* Mirror synchronization completed/failed. */
 | 
			
		||||
};
 | 
			
		||||
#define	ALL_ERRORS (SECTOR_ERROR | DEVICE_ERROR | PATH_ERROR | ADAPTOR_ERROR)
 | 
			
		||||
 | 
			
		||||
int dm_register_for_event(char *dso_name, char *device, enum event_type events);
 | 
			
		||||
int dm_unregister_for_event(char *dso_name, char *device,
 | 
			
		||||
			    enum event_type events);
 | 
			
		||||
int dm_get_next_registered_device(char **dso_name, char **device,
 | 
			
		||||
			    enum event_type *events);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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:
 | 
			
		||||
 */
 | 
			
		||||
@@ -19,7 +19,10 @@
 | 
			
		||||
#include <sys/file.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
 | 
			
		||||
#ifdef linux
 | 
			
		||||
#  include <malloc.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int _create_dir_recursive(const char *dir)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,9 @@ dmsetup \- low level logical volume management
 | 
			
		||||
.B dmsetup info 
 | 
			
		||||
.I [device_name]
 | 
			
		||||
.br
 | 
			
		||||
.B dmsetup info -c|-C|--columns [--noheadings] [-o name]
 | 
			
		||||
.I [device_name]
 | 
			
		||||
.br
 | 
			
		||||
.B dmsetup deps
 | 
			
		||||
.I [device_name]
 | 
			
		||||
.br
 | 
			
		||||
@@ -53,6 +56,13 @@ dmsetup \- low level logical volume management
 | 
			
		||||
.B dmsetup targets
 | 
			
		||||
.br
 | 
			
		||||
.B dmsetup version
 | 
			
		||||
.br
 | 
			
		||||
 | 
			
		||||
.B devmap_name
 | 
			
		||||
.I major minor
 | 
			
		||||
.br
 | 
			
		||||
.B devmap_name 
 | 
			
		||||
.I major:minor
 | 
			
		||||
.ad b
 | 
			
		||||
.SH DESCRIPTION
 | 
			
		||||
dmsetup manages logical devices that use the device-mapper driver.  
 | 
			
		||||
@@ -61,16 +71,38 @@ each sector (512 bytes) in the logical device.
 | 
			
		||||
 | 
			
		||||
The first argument to dmsetup is a command. 
 | 
			
		||||
The second argument is the logical device name or uuid.
 | 
			
		||||
 | 
			
		||||
Invoking the command as \fBdevmap_name\fP is equivalent to
 | 
			
		||||
.br
 | 
			
		||||
\fBdmsetup info -c --noheadings -j \fImajor\fB -m \fIminor\fP.
 | 
			
		||||
.SH OPTIONS
 | 
			
		||||
.IP \fB-c|-C|--columns
 | 
			
		||||
.br
 | 
			
		||||
Display output in columns rather than as Field: Value lines.
 | 
			
		||||
.IP \fB-j|--major\ \fImajor
 | 
			
		||||
.br
 | 
			
		||||
Specify the major number to use on creation.
 | 
			
		||||
.IP \fB-j|--minor\ \fIminor
 | 
			
		||||
Specify the major number.
 | 
			
		||||
.IP \fB-m|--minor\ \fIminor
 | 
			
		||||
.br
 | 
			
		||||
Specify the minor number to use on creation.
 | 
			
		||||
Specify the minor number.
 | 
			
		||||
.IP \fB-n|--noheadings
 | 
			
		||||
.br
 | 
			
		||||
Suppress the headings line when using columnar output.
 | 
			
		||||
.IP \fB--noopencount
 | 
			
		||||
.br
 | 
			
		||||
Tell the kernel not to supply the open reference count for the device.
 | 
			
		||||
.IP \fB--notable
 | 
			
		||||
.br
 | 
			
		||||
When creating a device, don't load any table.
 | 
			
		||||
.IP \fB-o|--options
 | 
			
		||||
.br
 | 
			
		||||
Specify which fields to display.  Only \fB-o\ name\fP is supported.
 | 
			
		||||
.IP \fB-r|--readonly
 | 
			
		||||
.br
 | 
			
		||||
Set the table being loaded read-only.
 | 
			
		||||
.IP \fB-u|--uuid
 | 
			
		||||
.br
 | 
			
		||||
Specify the uuid.
 | 
			
		||||
.IP \fB-v|--verbose [-v|--verbose]
 | 
			
		||||
.br
 | 
			
		||||
Produce additional output.
 | 
			
		||||
 
 | 
			
		||||
@@ -91,10 +91,10 @@ The approximate amount of space to be set aside for each metadata area.
 | 
			
		||||
.BR \-\-metadatacopies " copies"
 | 
			
		||||
The number of metadata areas to set aside on each PV.  Currently
 | 
			
		||||
this can be 0, 1 or 2.  
 | 
			
		||||
If set to 2 (the default), two copies of the volume group metadata 
 | 
			
		||||
If set to 2, two copies of the volume group metadata 
 | 
			
		||||
are held on the PV, one at the front of the PV and one at the end.  
 | 
			
		||||
If set to 1, one copy is kept at the front of the PV (starting in the
 | 
			
		||||
5th sector).
 | 
			
		||||
If set to 1 (the default), one copy is kept at the front of the PV 
 | 
			
		||||
(starting in the 5th sector).
 | 
			
		||||
If set to 0, no copies are kept on this PV - you might wish to use this
 | 
			
		||||
with VGs containing large numbers of PVs.  But if you do this and
 | 
			
		||||
then later use \fBvgsplit\fP you must ensure that each VG is still going 
 | 
			
		||||
 
 | 
			
		||||
@@ -33,29 +33,44 @@ previously configured for LVM with
 | 
			
		||||
.SH OPTIONS
 | 
			
		||||
See \fBlvm\fP for common options.
 | 
			
		||||
.TP
 | 
			
		||||
.BR \-A ", " \-\-autobackup " {" y | n }
 | 
			
		||||
Controls automatic backup of VG metadata after the change (see
 | 
			
		||||
.BR vgcfgbackup (8)).
 | 
			
		||||
Default is yes.
 | 
			
		||||
.TP
 | 
			
		||||
.BR \-l ", " \-\-maxlogicalvolumes " " \fIMaxLogicalVolumes\fR
 | 
			
		||||
Sets the maximum possible logical volume count.
 | 
			
		||||
More logical volumes can't be created in this volume group.
 | 
			
		||||
Absolute maximum is 256.
 | 
			
		||||
Sets the maximum number of logical volumes allowed in this
 | 
			
		||||
volume group. 
 | 
			
		||||
The setting can be changed with \fBvgchange\fP.
 | 
			
		||||
For volume groups with metadata in lvm1 format, the limit
 | 
			
		||||
and default value is 255.  
 | 
			
		||||
If the metadata uses lvm2 format, the default value is 0
 | 
			
		||||
which removes this restriction: there is then no limit.
 | 
			
		||||
.TP
 | 
			
		||||
.BR \-p ", " \-\-maxphysicalvolumes " " \fIMaxPhysicalVolumes\fR
 | 
			
		||||
Sets the maximum possible physical volume count.
 | 
			
		||||
More physical volumes can't be included in this volume group.
 | 
			
		||||
Absolute maximum is 256.
 | 
			
		||||
Sets the maximum number of physical volumes that can belong
 | 
			
		||||
to this volume group.
 | 
			
		||||
The setting can be changed with \fBvgchange\fP.
 | 
			
		||||
For volume groups with metadata in lvm1 format, the limit
 | 
			
		||||
and default value is 255.  
 | 
			
		||||
If the metadata uses lvm2 format, the default value is 0
 | 
			
		||||
which removes this restriction: there is then no limit.
 | 
			
		||||
If you have a large number of physical volumes in
 | 
			
		||||
a volume group with metadata in lvm2 format, 
 | 
			
		||||
for tool performance reasons, you should consider 
 | 
			
		||||
some use of \fB--metadatacopies 0\fP
 | 
			
		||||
as described in \fBpvcreate(8)\fP.
 | 
			
		||||
.TP
 | 
			
		||||
.BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize\fR[\fBkKmMgGtT\fR]
 | 
			
		||||
Sets the physical extent size on physical volumes of this volume group.
 | 
			
		||||
A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes
 | 
			
		||||
is the default if no suffix is present.  Values can be from 8 KB to 16 GB in
 | 
			
		||||
powers of 2. The default of 4 MB causes maximum LV sizes of ~256GB because as
 | 
			
		||||
many as ~64k extents are supported per LV. In case larger maximum LV sizes are
 | 
			
		||||
needed (later), you need to set the PE size to a larger value as well. Later
 | 
			
		||||
changes of the PE size in an existing VG are not supported.
 | 
			
		||||
powers of 2.  The default is 4 MB.
 | 
			
		||||
Once this value has been set, it is difficult to change it without recreating
 | 
			
		||||
the volume group which would involve backing up and restoring data on any 
 | 
			
		||||
logical volumes.
 | 
			
		||||
If the volume group metadata uses lvm1 format, there is a limit of 65534
 | 
			
		||||
extents in each logical volume, so the default of 4 MB leads to a maximum 
 | 
			
		||||
logical volume size of around 256GB.
 | 
			
		||||
If the volume group metadata uses lvm2 format there is no such restriction,
 | 
			
		||||
although having a large number of extents will slow down
 | 
			
		||||
the tools but have no impact on I/O performance to the logical volume.
 | 
			
		||||
The 2.4 kernel has a limitation of 2TB per block device.
 | 
			
		||||
.SH EXAMPLES
 | 
			
		||||
To create a volume group named
 | 
			
		||||
.B test_vg 
 | 
			
		||||
@@ -67,11 +82,6 @@ with default physical extent size of 4MB:
 | 
			
		||||
\	vgcreate test_vg /dev/sdk1 /dev/sdl1
 | 
			
		||||
 | 
			
		||||
.fi
 | 
			
		||||
To limit kernel memory usage, there is a limit of 65536 physical extents
 | 
			
		||||
(PE) per logical volume, so the PE size determines the maximum logical volume
 | 
			
		||||
size.  The default PE size of 4MB limits a single logical volume to 256GB (see
 | 
			
		||||
the -s option to raise that limit).
 | 
			
		||||
There is also (as of Linux 2.4) a kernel limitation of 2TB per block device.
 | 
			
		||||
.SH SEE ALSO
 | 
			
		||||
.BR lvm (8),
 | 
			
		||||
.BR pvdisplay (8),
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user