r230 - in devmapper/trunk: . dmeventd include lib lib/ioctl lib/mm

Bastian Blank waldi at costa.debian.org
Fri Dec 2 18:59:42 UTC 2005


Author: waldi
Date: Fri Dec  2 18:59:40 2005
New Revision: 230

Added:
   devmapper/trunk/dmeventd/
   devmapper/trunk/dmeventd/.exported_symbols
   devmapper/trunk/dmeventd/Makefile.in
   devmapper/trunk/dmeventd/dmeventd.c
   devmapper/trunk/dmeventd/dmeventd.h
   devmapper/trunk/dmeventd/libdevmapper-event.c
   devmapper/trunk/dmeventd/libdevmapper-event.h
Modified:
   devmapper/trunk/   (props changed)
   devmapper/trunk/Makefile.in
   devmapper/trunk/VERSION
   devmapper/trunk/WHATS_NEW
   devmapper/trunk/configure
   devmapper/trunk/configure.in
   devmapper/trunk/include/.symlinks
   devmapper/trunk/lib/.exported_symbols
   devmapper/trunk/lib/ioctl/libdm-iface.c
   devmapper/trunk/lib/ioctl/libdm-targets.h
   devmapper/trunk/lib/libdevmapper.h
   devmapper/trunk/lib/libdm-deptree.c
   devmapper/trunk/lib/mm/dbg_malloc.c
Log:
Merge /devmapper/upstream/current (1.02.02).


Modified: devmapper/trunk/Makefile.in
==============================================================================
--- devmapper/trunk/Makefile.in	(original)
+++ devmapper/trunk/Makefile.in	Fri Dec  2 18:59:40 2005
@@ -24,6 +24,10 @@
   SUBDIRS += po
 endif
 
+ifeq ("@DMEVENTD@", "yes")
+  SUBDIRS += dmeventd
+endif
+
 SUBDIRS += lib dmsetup
 
 ifeq ($(MAKECMDGOALS),distclean)
@@ -38,7 +42,8 @@
 
 lib: include
 dmsetup: lib
-dmeventd: lib multilog
+# dmeventd: lib multilog
+dmeventd: lib
 po: dmsetup dmeventd
 
 ifeq ("@INTL@", "yes")

Modified: devmapper/trunk/VERSION
==============================================================================
--- devmapper/trunk/VERSION	(original)
+++ devmapper/trunk/VERSION	Fri Dec  2 18:59:40 2005
@@ -1 +1 @@
-1.02.00 (2005-11-10)
+1.02.02 (2005-12-02)

Modified: devmapper/trunk/WHATS_NEW
==============================================================================
--- devmapper/trunk/WHATS_NEW	(original)
+++ devmapper/trunk/WHATS_NEW	Fri Dec  2 18:59:40 2005
@@ -1,3 +1,16 @@
+Version 1.02.02 - 2 Dec 2005
+============================
+  dmeventd added.
+  Export dm_task_update_nodes.
+  Use names instead of numbers in messages when ioctls fail.
+
+Version 1.02.01 - 23 Nov 2005
+=============================
+  Resume snapshot-origins last.
+  Drop leading zeros from dm_format_dev.
+  Suppress attempt to reload identical table.
+  Additional LVM- prefix matching for transitional period.
+
 Version 1.02.00 - 10 Nov 2005
 =============================
   Added activation functions to library.

Modified: devmapper/trunk/configure
==============================================================================
--- devmapper/trunk/configure	(original)
+++ devmapper/trunk/configure	Fri Dec  2 18:59:40 2005
@@ -310,7 +310,7 @@
 #endif"
 
 ac_default_prefix=/usr
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB LIBOBJS MSGFMT JOBS STATIC_LINK OWNER GROUP interface kerneldir missingkernel kernelvsn tmpdir COPTIMISE_FLAG CLDFLAGS LDDEPS LIB_SUFFIX DEBUG DM_LIB_VERSION COMPAT DMIOCTLS LOCALEDIR INTL_PACKAGE INTL DEVICE_UID DEVICE_GID DEVICE_MODE LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB LIBOBJS MSGFMT JOBS STATIC_LINK OWNER GROUP interface kerneldir missingkernel kernelvsn tmpdir COPTIMISE_FLAG CLDFLAGS LDDEPS LIB_SUFFIX DEBUG DM_LIB_VERSION COMPAT DMIOCTLS LOCALEDIR INTL_PACKAGE INTL DEVICE_UID DEVICE_GID DEVICE_MODE DMEVENTD LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -850,6 +850,7 @@
   --enable-debug          Enable debugging
   --enable-compat         Enable support for old device-mapper versions
   --disable-driver        Disable calls to device-mapper in the kernel
+  --enable-dmeventd       Build the new event daemon
   --enable-static_link    Use this to link the tools to their libraries
                           statically.  Default is dynamic linking
   --disable-selinux       Disable selinux support
@@ -2057,7 +2058,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2115,7 +2117,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2231,7 +2234,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2285,7 +2289,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2330,7 +2335,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2374,7 +2380,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2955,7 +2962,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3027,7 +3035,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3081,7 +3090,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3152,7 +3162,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3206,7 +3217,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3273,7 +3285,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3438,7 +3451,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3508,7 +3522,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3590,7 +3605,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3727,7 +3743,6 @@
 echo "$as_me:$LINENO: checking $ac_header usability" >&5
 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
 cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
@@ -3738,11 +3753,21 @@
 _ACEOF
 rm -f conftest.$ac_objext
 if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>&5
+  (eval $ac_compile) 2>conftest.er1
   ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-         { ac_try='test -s conftest.$ac_objext'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3755,7 +3780,7 @@
 
 ac_header_compiler=no
 fi
-rm -f conftest.$ac_objext conftest.$ac_ext
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
 echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
 echo "${ECHO_T}$ac_header_compiler" >&6
 
@@ -3763,7 +3788,6 @@
 echo "$as_me:$LINENO: checking $ac_header presence" >&5
 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
 cat >conftest.$ac_ext <<_ACEOF
-#line $LINENO "configure"
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
@@ -3781,6 +3805,7 @@
   (exit $ac_status); } >/dev/null; then
   if test -s conftest.err; then
     ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
   else
     ac_cpp_err=
   fi
@@ -3800,33 +3825,32 @@
 echo "${ECHO_T}$ac_header_preproc" >&6
 
 # So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc in
-  yes:no )
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
     { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
-echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
-    (
-      cat <<\_ASBOX
-## ------------------------------------ ##
-## Report this to bug-autoconf at gnu.org. ##
-## ------------------------------------ ##
-_ASBOX
-    ) |
-      sed "s/^/$as_me: WARNING:     /" >&2
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
     ;;
-  no:yes )
+  no:yes:* )
     { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
-    { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
-echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
     { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
     (
       cat <<\_ASBOX
-## ------------------------------------ ##
-## Report this to bug-autoconf at gnu.org. ##
-## ------------------------------------ ##
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists.  ##
+## ------------------------------------------ ##
 _ASBOX
     ) |
       sed "s/^/$as_me: WARNING:     /" >&2
@@ -3837,7 +3861,7 @@
 if eval "test \"\${$as_ac_Header+set}\" = set"; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
-  eval "$as_ac_Header=$ac_header_preproc"
+  eval "$as_ac_Header=\$ac_header_preproc"
 fi
 echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
@@ -3928,7 +3952,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3988,7 +4013,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4061,7 +4087,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4104,7 +4131,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4175,7 +4203,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4240,7 +4269,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4312,7 +4342,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4373,7 +4404,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4484,7 +4516,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -4615,7 +4648,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -5026,7 +5060,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -5120,7 +5155,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -5293,6 +5329,15 @@
 fi;
 
 ################################################################################
+# Check whether --enable-dmeventd or --disable-dmeventd was given.
+if test "${enable_dmeventd+set}" = set; then
+  enableval="$enable_dmeventd"
+  DMEVENTD=$enableval
+else
+  DMEVENTD=no
+fi;
+
+################################################################################
 # Check whether --enable-static_link or --disable-static_link was given.
 if test "${enable_static_link+set}" = set; then
   enableval="$enable_static_link"
@@ -5357,7 +5402,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -5433,7 +5479,8 @@
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -5761,8 +5808,9 @@
 
 
 
+
 ################################################################################
-                                                                                          ac_config_files="$ac_config_files Makefile make.tmpl include/Makefile dmsetup/Makefile lib/Makefile lib/libdm-common.h kernel/Makefile man/Makefile po/Makefile"
+                                                                                                    ac_config_files="$ac_config_files Makefile make.tmpl include/Makefile dmsetup/Makefile lib/Makefile lib/libdm-common.h dmeventd/Makefile kernel/Makefile man/Makefile po/Makefile"
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
@@ -6320,6 +6368,7 @@
   "dmsetup/Makefile" ) CONFIG_FILES="$CONFIG_FILES dmsetup/Makefile" ;;
   "lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;;
   "lib/libdm-common.h" ) CONFIG_FILES="$CONFIG_FILES lib/libdm-common.h" ;;
+  "dmeventd/Makefile" ) CONFIG_FILES="$CONFIG_FILES dmeventd/Makefile" ;;
   "kernel/Makefile" ) CONFIG_FILES="$CONFIG_FILES kernel/Makefile" ;;
   "man/Makefile" ) CONFIG_FILES="$CONFIG_FILES man/Makefile" ;;
   "po/Makefile" ) CONFIG_FILES="$CONFIG_FILES po/Makefile" ;;
@@ -6460,6 +6509,7 @@
 s, at DEVICE_UID@,$DEVICE_UID,;t t
 s, at DEVICE_GID@,$DEVICE_GID,;t t
 s, at DEVICE_MODE@,$DEVICE_MODE,;t t
+s, at DMEVENTD@,$DMEVENTD,;t t
 s, at LTLIBOBJS@,$LTLIBOBJS,;t t
 CEOF
 

Modified: devmapper/trunk/configure.in
==============================================================================
--- devmapper/trunk/configure.in	(original)
+++ devmapper/trunk/configure.in	Fri Dec  2 18:59:40 2005
@@ -176,6 +176,11 @@
 DMIOCTLS=$enableval)
 
 ################################################################################
+dnl -- Enable dmeventd
+AC_ARG_ENABLE(dmeventd,   [  --enable-dmeventd       Build the new event daemon],
+DMEVENTD=$enableval, DMEVENTD=no)
+
+################################################################################
 dnl -- Enables staticly-linked tools
 AC_ARG_ENABLE(static_link, [  --enable-static_link    Use this to link the tools to their libraries
                           statically.  Default is dynamic linking],  STATIC_LINK=$enableval, STATIC_LINK=no)
@@ -349,6 +354,7 @@
 AC_SUBST(DEVICE_UID)
 AC_SUBST(DEVICE_GID)
 AC_SUBST(DEVICE_MODE)
+AC_SUBST(DMEVENTD)
 
 
 ################################################################################
@@ -361,6 +367,7 @@
 dmsetup/Makefile							\
 lib/Makefile							 	\
 lib/libdm-common.h						 	\
+dmeventd/Makefile						 	\
 kernel/Makefile								\
 man/Makefile								\
 po/Makefile								\

Added: devmapper/trunk/dmeventd/.exported_symbols
==============================================================================
--- (empty file)
+++ devmapper/trunk/dmeventd/.exported_symbols	Fri Dec  2 18:59:40 2005
@@ -0,0 +1,5 @@
+dm_register_for_event
+dm_unregister_for_event
+dm_get_registered_device
+dm_set_event_timeout
+dm_get_event_timeout

Added: devmapper/trunk/dmeventd/Makefile.in
==============================================================================
--- (empty file)
+++ devmapper/trunk/dmeventd/Makefile.in	Fri Dec  2 18:59:40 2005
@@ -0,0 +1,56 @@
+#
+# 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
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+interface = @interface@
+
+SOURCES = libdevmapper-event.c \
+	  dmeventd.c
+
+LIB_STATIC = libdevmapper-event.a
+
+ifeq ("@LIB_SUFFIX@","dylib")
+  LIB_SHARED = libdevmapper-event.dylib
+else
+  LIB_SHARED = libdevmapper-event.so
+endif
+
+CLDFLAGS += -ldl -ldevmapper -lpthread
+
+include ../make.tmpl
+
+.PHONY: install_dynamic install_static
+
+INSTALL_TYPE = install_dynamic
+
+ifeq ("@STATIC_LINK@", "yes")
+  INSTALL_TYPE += install_static
+endif
+
+install: $(INSTALL_TYPE)
+
+install_dynamic: libdevmapper-event.$(LIB_SUFFIX)
+	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
+		$(libdir)/libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION)
+	$(LN_S) -f libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION) \
+		$(libdir)/libdevmapper-event.$(LIB_SUFFIX)
+	$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.h \
+		$(includedir)/libdevmapper-event.h
+
+install_static: libdevmapper-event.a
+	$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
+		$(libdir)/libdevmapper-event.a.$(LIB_VERSION)
+	$(LN_S) -f libdevmapper-event.a.$(LIB_VERSION) $(libdir)/libdevmapper-event.a
+

Added: devmapper/trunk/dmeventd/dmeventd.c
==============================================================================
--- (empty file)
+++ devmapper/trunk/dmeventd/dmeventd.c	Fri Dec  2 18:59:40 2005
@@ -0,0 +1,1286 @@
+/*
+ * 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
+ */
+
+/*
+ * dmeventd - dm event daemon to monitor active mapped devices
+ */
+
+#include "libdevmapper.h"
+#include "libdevmapper-event.h"
+#include "list.h"
+#include "dmeventd.h"
+//#include "libmultilog.h"
+#include "log.h"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#ifdef linux
+#include <malloc.h>
+#endif
+
+/* FIXME Use dm library */
+#define	dbg_malloc(x...)	malloc(x)
+#define	dbg_strdup(x...)	strdup(x)
+#define	dbg_free(x...)		free(x)
+
+/* List (un)link macros. */
+#define	LINK(x, head)		list_add(head, &(x)->list)
+#define	LINK_DSO(dso)		LINK(dso, &dso_registry)
+#define	LINK_THREAD(thread)	LINK(thread, &thread_registry)
+
+#define	UNLINK(x)		list_del(&(x)->list)
+#define	UNLINK_DSO(x)		UNLINK(x)
+#define	UNLINK_THREAD(x)	UNLINK(x)
+
+#define DAEMON_NAME "dmeventd"
+
+/* Global mutex for list accesses. */
+static pthread_mutex_t mutex;
+
+/* Data kept about a DSO. */
+struct dso_data {
+	struct list list;
+
+	char *dso_name; /* DSO name (eg, "evms", "dmraid", "lvm2"). */
+
+	void *dso_handle; /* Opaque handle as returned from dlopen(). */
+	unsigned int ref_count; /* Library reference count. */
+
+	/*
+	 * Event processing.
+	 *
+	 * The DSO can do whatever appropriate steps if an event happens
+	 * such as changing the mapping in case a mirror fails, update
+	 * the application metadata etc.
+	 */
+	void (*process_event)(const char *device, enum dm_event_type event);
+
+	/*
+	 * Device registration.
+	 *
+	 * When an application registers a device for an event, the DSO
+	 * can carry out appropriate steps so that a later call to
+	 * the process_event() function is sane (eg, read metadata
+	 * and activate a mapping).
+	 */
+	int (*register_device)(const char *device);
+
+	/*
+	 * Device unregistration.
+	 *
+	 * In case all devices of a mapping (eg, RAID10) are unregistered
+	 * for events, the DSO can recognize this and carry out appropriate
+	 * steps (eg, deactivate mapping, metadata update).
+	 */
+	int (*unregister_device)(const char *device);
+};
+static LIST_INIT(dso_registry);
+
+/* Structure to keep parsed register variables from client message. */
+struct message_data {
+	char *dso_name;		/* Name of DSO. */
+	char *device_path;	/* Mapped device path. */
+	union {
+		char *str;	/* Events string as fetched from message. */
+		enum dm_event_type field;	/* Events bitfield. */
+	} events;
+	union {
+		char *str;
+		uint32_t secs;
+	} timeout;
+	struct dm_event_daemon_message *msg;	/* Pointer to message buffer. */
+};
+
+/*
+ * Housekeeping of thread+device states.
+ *
+ * One thread per mapped device which can block on it until an event
+ * occurs and the event processing function of the DSO gets called.
+ */
+struct thread_status {
+	struct list	list;
+
+	pthread_t		thread;
+
+	struct dso_data *dso_data;/* DSO this thread accesses. */
+	
+	char *device_path;	/* Mapped device path. */
+	int event_nr;           /* event number */
+	enum dm_event_type events;	/* bitfield for event filter. */
+	enum dm_event_type current_events;/* bitfield for occured events. */
+	enum dm_event_type processed_events;/* bitfield for processed events. */
+	time_t next_time;
+	uint32_t timeout;
+	struct list timeout_list;
+};
+static LIST_INIT(thread_registry);
+
+static int timeout_running;
+static LIST_INIT(timeout_registry);
+static pthread_mutex_t timeout_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t timeout_cond = PTHREAD_COND_INITIALIZER;
+
+/* Allocate/free the status structure for a monitoring thread. */
+static struct thread_status *alloc_thread_status(struct message_data *data,
+						 struct dso_data *dso_data)
+{
+	struct thread_status *ret = (typeof(ret)) dbg_malloc(sizeof(*ret));
+
+	if (ret) {
+		if (!memset(ret, 0, sizeof(*ret)) ||
+		    !(ret->device_path = dbg_strdup(data->device_path))) {
+			dbg_free(ret);
+			ret = NULL;
+		} else {
+			ret->dso_data = dso_data;
+			ret->events   = data->events.field;
+			ret->timeout  = data->timeout.secs;
+			list_init(&ret->timeout_list);
+		}
+	}
+
+	return ret;
+}
+
+static void free_thread_status(struct thread_status *thread)
+{
+	dbg_free(thread->device_path);
+	dbg_free(thread);
+}
+
+/* Allocate/free DSO data. */
+static struct dso_data *alloc_dso_data(struct message_data *data)
+{
+	struct dso_data *ret = (typeof(ret)) dbg_malloc(sizeof(*ret));
+
+	if (ret) {
+		if (!memset(ret, 0, sizeof(*ret)) ||
+		    !(ret->dso_name = dbg_strdup(data->dso_name))) {
+			dbg_free(ret);
+			ret = NULL;
+		}
+	}
+
+	return ret;
+}
+
+static void free_dso_data(struct dso_data *data)
+{
+	dbg_free(data->dso_name);
+	dbg_free(data);
+}
+
+/* FIXME: Factor out. */
+static char *dm_basename(char *str)
+{
+	char *p = strrchr(str, '/');
+
+	return p ? p + 1 : str;
+}
+
+/*
+ * Fetch a string off src and duplicate it into *ptr.
+ * Pay attention to 0 lenght strings.
+ */
+/* FIXME: move to separate module to share with the client lib. */
+static const char delimiter = ' ';
+static int fetch_string(char **ptr, char **src)
+{
+	int ret = 0;
+	char *p;
+	size_t len;
+
+	if ((p = strchr(*src, delimiter)))
+		*p = 0;
+
+	if ((*ptr = dbg_strdup(*src))) {
+		if ((len = strlen(*ptr)))
+			*src += len;
+		else {
+			dbg_free(*ptr);
+			*ptr = NULL;
+		}
+
+		(*src)++;
+		ret = 1;
+	}
+
+	if (p)
+		*p = delimiter;
+
+	return ret;
+}
+
+/* Free message memory. */
+static void free_message(struct message_data *message_data)
+{
+	if (message_data->dso_name)
+		dbg_free(message_data->dso_name);
+
+	if (message_data->device_path)
+		dbg_free(message_data->device_path);
+}
+
+/* Parse a register message from the client. */
+static int parse_message(struct message_data *message_data)
+{
+	char *p = message_data->msg->msg;
+
+	/*
+	 * Retrieve application identifier, mapped device
+	 * path and events # string from message.
+	 */
+	if (fetch_string(&message_data->dso_name, &p) &&
+	    fetch_string(&message_data->device_path, &p) &&
+	    fetch_string(&message_data->events.str, &p) &&
+	    fetch_string(&message_data->timeout.str, &p)) {
+		if (message_data->events.str) {
+			enum dm_event_type i = atoi(message_data->events.str);
+
+			/*
+			 * Free string representaion of events.
+			 * Not needed an more.
+			 */
+			dbg_free(message_data->events.str);
+			message_data->events.field = i;
+		}
+		if (message_data->timeout.str) {
+			uint32_t secs = atoi(message_data->timeout.str);
+			dbg_free(message_data->timeout.str);
+			message_data->timeout.secs = secs ? secs :
+							    DM_EVENT_DEFAULT_TIMEOUT;
+		}
+
+		return 1;
+	}
+
+	return 0;
+};
+
+/* Global mutex to lock access to lists et al. */
+static int lock_mutex(void)
+{
+	return pthread_mutex_lock(&mutex);
+}
+
+static int unlock_mutex(void)
+{
+	return pthread_mutex_unlock(&mutex);
+}
+
+/* Store pid in pidfile. */
+static int storepid(int lf)
+{
+	int len;
+	char pid[8];
+
+	if ((len = snprintf(pid, sizeof(pid), "%u\n", getpid())) < 0)
+		return 0;
+
+	if (len > sizeof(pid))
+		len = sizeof(pid);
+
+	if (write(lf, pid, len) != len)
+		return 0;
+
+	fsync(lf);
+
+	return 1;
+}
+
+
+/* Check, if a device exists. */
+static int device_exists(char *device)
+{
+	struct stat st_buf;
+
+	return !stat(device, &st_buf) && S_ISBLK(st_buf.st_mode);
+}
+
+/*
+ * Find an existing thread for a device.
+ *
+ * Mutex must be hold when calling this.
+ */
+static struct thread_status *lookup_thread_status(struct message_data *data)
+{
+	struct thread_status *thread;
+
+	list_iterate_items(thread, &thread_registry) {
+		if (!strcmp(data->device_path, thread->device_path))
+			return thread;
+	}
+
+	return NULL;
+}
+
+
+/* Cleanup at exit. */
+static void exit_dm_lib(void)
+{
+	dm_lib_release();
+	dm_lib_exit();
+}
+
+/* Derive error case from target parameter string. */
+/* FIXME Remove? */
+static int error_detected(struct thread_status *thread, char *params) __attribute__ ((unused));
+static int error_detected(struct thread_status *thread, char *params)
+{
+	size_t len;
+/*
+  Leave it to the DSO to decide how to interpret the status info
+	if ((len = strlen(params)) &&
+	    params[len - 1] == 'F') {
+*/
+	if (params && (len = strlen(params))) {
+		thread->current_events |= DM_EVENT_DEVICE_ERROR;
+		return 1;
+	}
+
+	return 0;
+}
+
+static void exit_timeout(void *unused)
+{
+	timeout_running = 0;
+	pthread_mutex_unlock(&timeout_mutex);
+}
+
+/* Wake up monitor threads every so often. */
+static void *timeout_thread(void *unused)
+{
+	struct timespec timeout;
+	time_t curr_time;
+
+	timeout.tv_nsec = 0;
+	pthread_cleanup_push(exit_timeout, NULL);
+	pthread_mutex_lock(&timeout_mutex);
+
+	while (!list_empty(&timeout_registry)) {
+		struct thread_status *thread;
+
+		timeout.tv_sec = (time_t)-1;
+		curr_time = time(NULL);
+
+		list_iterate_items_gen(thread, &timeout_registry,
+				       timeout_list) {
+			if (thread->next_time < curr_time) {
+				thread->next_time = curr_time + thread->timeout;
+				pthread_kill(thread->thread, SIGALRM);
+			}
+
+			if (thread->next_time < timeout.tv_sec)
+				timeout.tv_sec = thread->next_time;
+		}
+
+		pthread_cond_timedwait(&timeout_cond, &timeout_mutex, &timeout);
+	}
+
+	pthread_cleanup_pop(1);
+
+	return NULL;
+}
+
+static int register_for_timeout(struct thread_status *thread)
+{
+	int ret = 0;
+
+	pthread_mutex_lock(&timeout_mutex);
+
+	thread->next_time = time(NULL) + thread->timeout;
+
+	if (list_empty(&thread->timeout_list)) {
+		list_add(&timeout_registry, &thread->timeout_list);
+		if (timeout_running)
+			pthread_cond_signal(&timeout_cond);
+	}
+
+	if (!timeout_running) {
+		pthread_t timeout_id;
+
+		if (!(ret = -pthread_create(&timeout_id, NULL,
+					    timeout_thread, NULL)))
+			timeout_running = 1;
+	}
+
+	pthread_mutex_unlock(&timeout_mutex);
+
+	return ret;
+}
+
+static void unregister_for_timeout(struct thread_status *thread)
+{
+	pthread_mutex_lock(&timeout_mutex);
+	if (!list_empty(&thread->timeout_list)) {
+		list_del(&thread->timeout_list);
+		list_init(&thread->timeout_list);
+	}
+	pthread_mutex_unlock(&timeout_mutex);
+}
+
+static void no_intr_log(int level, const char *file, int line,
+		       const char *f, ...)
+{
+	va_list ap;
+
+	if (errno == EINTR)
+		return;
+	if (level > _LOG_WARN)
+		return;
+
+	va_start(ap, f);
+
+	if (level < _LOG_WARN)
+		vfprintf(stderr, f, ap);
+	else
+		vprintf(f, ap);
+
+	va_end(ap);
+
+	if (level < _LOG_WARN)
+		fprintf(stderr, "\n");
+	else
+		fprintf(stdout, "\n");
+}
+
+static sigset_t unblock_sigalrm(void)
+{
+	sigset_t set, old;
+
+	sigemptyset(&set);
+	sigaddset(&set, SIGALRM);
+	pthread_sigmask(SIG_UNBLOCK, &set, &old);
+	return old;
+}
+
+/* Wait on a device until an event occurs. */
+static int event_wait(struct thread_status *thread)
+{
+	sigset_t set;
+	int ret = 0;
+/*
+	void *next = NULL;
+	char *params, *target_type;
+	uint64_t start, length;
+*/
+	struct dm_task *dmt;
+	struct dm_info info;
+
+	if (!(dmt = dm_task_create(DM_DEVICE_WAITEVENT)))
+		return 0;
+
+	if (!(ret = dm_task_set_name(dmt, dm_basename(thread->device_path))) ||
+	    !(ret = dm_task_set_event_nr(dmt, thread->event_nr)))
+		goto out;
+
+	/*
+	 * This is so that you can break out of waiting on an event,
+	 * either for a timeout event, or to cancel the thread.
+	 */
+	set = unblock_sigalrm();
+	dm_log_init(no_intr_log);
+	errno = 0;
+	if ((ret = dm_task_run(dmt))) {
+/*
+		do {
+			params = NULL;
+			next = dm_get_next_target(dmt, next, &start, &length,
+						  &target_type, &params);
+
+			log_error("%s: %s\n", __func__, params);
+			if ((ret = error_detected(thread, params)))
+				break;
+		} while(next);
+*/
+		thread->current_events |= DM_EVENT_DEVICE_ERROR;
+		ret = 1;
+
+		/*
+		 * FIXME:  I am setting processed_events to zero here
+		 * because it is causing problems.  for example, the
+		 * mirror target emits a signal for INSYNC, then
+		 * subsequent events (device failures) are not handled
+		 */
+		thread->processed_events = 0;
+
+		if ((ret = dm_task_get_info(dmt, &info)))
+			thread->event_nr = info.event_nr;
+	} else if (thread->events & DM_EVENT_TIMEOUT && errno == EINTR) {
+		thread->current_events |= DM_EVENT_TIMEOUT;
+		ret = 1;
+		thread->processed_events = 0;
+	}
+
+	pthread_sigmask(SIG_SETMASK, &set, NULL);
+	dm_log_init(NULL);
+
+   out:
+	dm_task_destroy(dmt);
+
+	return ret;
+}
+
+/* Register a device with the DSO. */
+static int do_register_device(struct thread_status *thread)
+{
+	return thread->dso_data->register_device(thread->device_path);
+}
+
+/* Unregister a device with the DSO. */
+static int do_unregister_device(struct thread_status *thread)
+{
+	return thread->dso_data->unregister_device(thread->device_path);
+}
+
+/* Process an event in the DSO. */
+static void do_process_event(struct thread_status *thread)
+{
+	thread->dso_data->process_event(thread->device_path,
+					thread->current_events);
+}
+
+/* Thread cleanup handler to unregister device. */
+static void monitor_unregister(void *arg)
+{
+	struct thread_status *thread = arg;
+
+	if (!do_unregister_device(thread))
+		log_error("%s: %s unregister failed\n", __func__,
+			thread->device_path);
+}
+
+/* Device monitoring thread. */
+static void *monitor_thread(void *arg)
+{
+	struct thread_status *thread = arg;
+
+	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
+	pthread_cleanup_push(monitor_unregister, thread);
+
+	/* Wait for do_process_reques() to finish its task. */
+	lock_mutex();
+	unlock_mutex();
+
+	/* Loop forever awaiting/analyzing device events. */
+	while (1) {
+		thread->current_events = 0;
+
+		if (!event_wait(thread))
+			continue;
+
+		/*
+		 * Check against filter.
+		 *
+		 * If there's current events delivered from event_wait() AND
+		 * the device got registered for those events AND
+		 * those events haven't been processed yet, call
+		 * the DSO's process_event() handler.
+		 */
+		if (thread->events &
+		    thread->current_events &
+		    ~thread->processed_events) {
+			do_process_event(thread);
+			thread->processed_events |= thread->current_events;
+		}
+	}
+
+	pthread_cleanup_pop(0);
+}
+
+/* Create a device monitoring thread. */
+/* FIXME: call this with mutex hold ? */
+static int create_thread(struct thread_status *thread)
+{
+	return pthread_create(&thread->thread, NULL, monitor_thread, thread);
+}
+
+static int terminate_thread(struct thread_status *thread)
+{
+	int ret;
+
+	if ((ret = pthread_cancel(thread->thread)))
+		return ret;
+
+	return pthread_kill(thread->thread, SIGALRM);
+}
+
+/* DSO reference counting. */
+static void lib_get(struct dso_data *data)
+{
+	data->ref_count++;
+}
+
+static void lib_put(struct dso_data *data)
+{
+	if (!--data->ref_count) {
+		dlclose(data->dso_handle);
+		UNLINK_DSO(data);
+		free_dso_data(data);
+	}
+}
+
+/* Find DSO data. */
+static struct dso_data *lookup_dso(struct message_data *data)
+{
+	struct dso_data *dso_data, *ret = NULL;
+
+	lock_mutex();
+
+	list_iterate_items(dso_data, &dso_registry) {
+		if (!strcmp(data->dso_name, dso_data->dso_name)) {
+			lib_get(dso_data);
+			ret = dso_data;
+			break;
+		}
+	}
+
+	unlock_mutex();
+
+	return ret;
+}
+
+/* Lookup DSO symbols we need. */
+static int lookup_symbol(void *dl, struct dso_data *data,
+			 void **symbol, const char *name)
+{
+	if ((*symbol = dlsym(dl, name)))
+		return 1;
+
+	log_error("looking up %s symbol in %s\n", name, data->dso_name);
+
+	return 0;
+}
+
+static int lookup_symbols(void *dl, struct dso_data *data)
+{
+	return lookup_symbol(dl, data, (void*) &data->process_event,
+			     "process_event") &&
+	       lookup_symbol(dl, data, (void*) &data->register_device,
+			     "register_device") &&
+	       lookup_symbol(dl, data, (void*) &data->unregister_device,
+			     "unregister_device");
+}
+
+/* Create a DSO file name based on its name. */
+static char *create_dso_file_name(char *dso_name)
+{
+	char *ret;
+	static char prefix[] = "libdmeventd";
+	static char suffix[] = ".so";
+
+	if ((ret = dbg_malloc(strlen(prefix) +
+			      strlen(dso_name) +
+			      strlen(suffix) + 1)))
+		sprintf(ret, "%s%s%s", prefix, dso_name, suffix);
+
+	return ret;
+}
+
+/* Load an application specific DSO. */
+static struct dso_data *load_dso(struct message_data *data)
+{
+	void *dl;
+	struct dso_data *ret = NULL;
+	char *dso_file;
+
+	if (!(dso_file = create_dso_file_name(data->dso_name)))
+		return NULL;
+
+	if (!(dl = dlopen(dso_file, RTLD_NOW))){
+		log_error("%s\n", dlerror());
+		goto free_dso_file;
+	}
+
+	if (!(ret = alloc_dso_data(data)))
+		goto close;
+
+	if (!(lookup_symbols(dl, ret)))
+		goto free_all;
+
+	/*
+	 * Keep handle to close the library once
+	 * we've got no references to it any more.
+	 */
+	ret->dso_handle = dl;
+	lib_get(ret);
+
+	lock_mutex();
+	LINK_DSO(ret);
+	unlock_mutex();
+
+	goto free_dso_file;
+
+   free_all:
+	free_dso_data(ret);
+
+   close:
+	dlclose(dl);
+
+   free_dso_file:
+	dbg_free(dso_file);
+
+	return ret;
+}
+
+
+/* Return success on daemon active check. */
+static int active(struct message_data *message_data)
+{
+	return 0;
+}
+
+/*
+ * Register for an event.
+ *
+ * Only one caller at a time here, because we use
+ * a FIFO and lock it against multiple accesses.
+ */
+static int register_for_event(struct message_data *message_data)
+{
+	int ret = 0;
+	struct thread_status *thread, *thread_new = NULL;
+	struct dso_data *dso_data;
+
+	if (!device_exists(message_data->device_path)) {
+		stack;
+		ret = -ENODEV;
+		goto out;
+	}
+
+	if (!(dso_data = lookup_dso(message_data)) &&
+	    !(dso_data = load_dso(message_data))) {
+		stack;
+/* FIXME */
+#ifdef ELIBACC
+		ret = -ELIBACC;
+#else
+		ret = -ENODEV;
+#endif
+		goto out;
+	}
+		
+	/* Preallocate thread status struct to avoid deadlock. */
+	if (!(thread_new = alloc_thread_status(message_data, dso_data))) {
+		stack;
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	lock_mutex();
+
+	if (!(thread = lookup_thread_status(message_data))) {
+		unlock_mutex();
+
+		/*
+		 * FIXME: better do this asynchronously in the
+		 *        monitoring thread ?
+		 */
+		if (!(ret = do_register_device(thread_new)))
+			goto out;
+
+		thread = thread_new;
+		thread_new = NULL;
+
+		/* Try to create the monitoring thread for this device. */
+		lock_mutex();
+		if ((ret = -create_thread(thread))) {
+			unlock_mutex();
+			do_unregister_device(thread);
+			free_thread_status(thread);
+			goto out;
+		} else
+			LINK_THREAD(thread);
+	}
+
+	/* Or event # into events bitfield. */
+	thread->events |= message_data->events.field;
+
+	unlock_mutex(); 
+
+	/* FIXME - If you fail to register for timeout events, you
+	   still monitor all the other events. Is this the right
+	   action for newly created devices?  Also, you are still
+	   on the timeout registry, so if a timeout thread is
+	   successfully started up later, you will start receiving
+	   DM_EVENT_TIMEOUT events */
+	if (thread->events & DM_EVENT_TIMEOUT)
+		ret = -register_for_timeout(thread);
+
+   out:
+	/*
+	 * Deallocate thread status after releasing
+	 * the lock in case we haven't used it.
+	 */
+	if (thread_new)
+		free_thread_status(thread_new);
+
+	return ret;
+}
+
+/*
+ * Unregister for an event.
+ *
+ * Only one caller at a time here as with register_for_event().
+ */
+static int unregister_for_event(struct message_data *message_data)
+{
+	int ret = 0;
+	struct thread_status *thread;
+
+	/*
+	 * Clear event in bitfield and deactivate
+	 * monitoring thread in case bitfield is 0.
+	 */
+	lock_mutex();
+
+	if (!(thread = lookup_thread_status(message_data))) {
+		unlock_mutex();
+		ret = -ENODEV;
+		goto out;
+	}
+
+	thread->events &= ~message_data->events.field;
+
+	if (!(thread->events & DM_EVENT_TIMEOUT))
+		unregister_for_timeout(thread);
+	/*
+	 * In case there's no events to monitor on this device ->
+	 * unlink and terminate its monitoring thread.
+	 */
+	if (!thread->events)
+		UNLINK_THREAD(thread);
+
+	unlock_mutex();
+
+	if (!thread->events) {
+		/* turn codes negative */
+		if ((ret = -terminate_thread(thread)))
+			stack;
+		else {
+			pthread_join(thread->thread, NULL);
+			free_thread_status(thread);
+			lib_put(thread->dso_data);
+
+			lock_mutex();
+			if (list_empty(&thread_registry))
+				exit_dm_lib();
+			unlock_mutex();
+		}
+	}
+
+
+   out:
+	return ret;
+}
+
+/*
+ * Get registered device.
+ *
+ * Only one caller at a time here as with register_for_event().
+ */
+static int registered_device(struct message_data *message_data,
+			     struct thread_status *thread)
+{
+	struct dm_event_daemon_message *msg = message_data->msg;
+
+	snprintf(msg->msg, sizeof(msg->msg), "%s %s %u", 
+		 thread->dso_data->dso_name, thread->device_path,
+		 thread->events);
+
+	unlock_mutex();
+
+	return 0;
+}
+
+static int want_registered_device(char *dso_name, char *device_path,
+				  struct thread_status *thread)
+{
+	/* If DSO names and device paths are equal. */
+	if (dso_name && device_path)
+		return !strcmp(dso_name, thread->dso_data->dso_name) &&
+		       !strcmp(device_path, thread->device_path);
+
+	/* If DSO names are equal. */
+	if (dso_name)
+		return !strcmp(dso_name, thread->dso_data->dso_name);
+		
+	/* If device paths are equal. */
+	if (device_path)
+		return !strcmp(device_path, thread->device_path);
+
+	return 1;
+}
+
+static int _get_registered_device(struct message_data *message_data, int next)
+{
+	int hit = 0;
+	struct thread_status *thread;
+
+	lock_mutex();
+
+	/* Iterate list of threads checking if we want a particular one. */
+	list_iterate_items(thread, &thread_registry) {
+		if ((hit = want_registered_device(message_data->dso_name,
+						  message_data->device_path,
+						  thread)))
+			break;
+	}
+
+	/*
+	 * If we got a registered device and want the next one ->
+	 * fetch next conforming element off the list.
+	 */
+	if (hit) {
+		if (next) {
+			do {
+				if (list_end(&thread_registry, &thread->list))
+					goto out;
+				
+				thread = list_item(thread->list.n,
+						   struct thread_status);
+			} while (!want_registered_device(message_data->dso_name,
+							 NULL, thread));
+		}
+
+		return registered_device(message_data, thread);
+	}
+
+   out:
+	unlock_mutex();
+
+	return -ENOENT;
+}
+
+static int get_registered_device(struct message_data *message_data)
+{
+	return _get_registered_device(message_data, 0);
+}
+
+static int get_next_registered_device(struct message_data *message_data)
+{
+	return _get_registered_device(message_data, 1);
+}
+
+static int set_timeout(struct message_data *message_data)
+{
+	struct thread_status *thread;
+
+	lock_mutex();
+	if ((thread = lookup_thread_status(message_data)))
+		thread->timeout = message_data->timeout.secs; 
+	unlock_mutex();
+
+	return thread ? 0 : -ENODEV;
+}
+
+static int get_timeout(struct message_data *message_data)
+{
+	struct thread_status *thread;
+	struct dm_event_daemon_message *msg = message_data->msg;
+
+	lock_mutex();
+	if ((thread = lookup_thread_status(message_data)))
+		snprintf(msg->msg, sizeof(msg->msg),
+			 "%"PRIu32, thread->timeout);
+	unlock_mutex();
+
+	return thread ? 0 : -ENODEV;
+}
+	
+
+/* Initialize a fifos structure with path names. */
+static int init_fifos(struct dm_event_fifos *fifos)
+{
+	if (memset(fifos, 0, sizeof(*fifos))) {
+		fifos->client_path = DM_EVENT_FIFO_CLIENT;
+		fifos->server_path = DM_EVENT_FIFO_SERVER;
+
+		return 0;
+	}
+
+	return -ENOMEM;
+}
+
+/* Open fifos used for client communication. */
+static int open_fifos(struct dm_event_fifos *fifos)
+{
+	/* Blocks until client is ready to write. */
+	if ((fifos->server = open(fifos->server_path, O_WRONLY)) < 0) {
+		stack;
+		return -EXIT_FIFO_FAILURE;
+	}
+
+	/* Need to open read+write for select() to work. */
+        if ((fifos->client = open(fifos->client_path, O_RDWR)) < 0) {
+		stack;
+		close(fifos->server);
+		return -EXIT_FIFO_FAILURE;
+	}
+
+	return 0;
+}
+
+/*
+ * Read message from client making sure that data is available
+ * and a complete message is read.
+ */
+static int client_read(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
+{
+	int bytes = 0, ret = 0;
+	fd_set fds;
+
+	errno = 0;
+	while (bytes < sizeof(*msg) && errno != EOF) {
+		do {
+			/* Watch client read FIFO for input. */
+			FD_ZERO(&fds);
+			FD_SET(fifos->client, &fds);
+		} while (select(fifos->client+1, &fds, NULL, NULL, NULL) != 1);
+
+		ret = read(fifos->client, msg, sizeof(*msg) - bytes);
+		bytes += ret > 0 ? ret : 0;
+	}
+
+	return bytes == sizeof(*msg);
+}
+
+/*
+ * Write a message to the client making sure that it is ready to write.
+ */
+static int client_write(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
+{
+	int bytes = 0, ret = 0;
+	fd_set fds;
+
+	errno = 0;
+	while (bytes < sizeof(*msg) && errno != EIO) {
+		do {
+			/* Watch client write FIFO to be ready for output. */
+			FD_ZERO(&fds);
+			FD_SET(fifos->server, &fds);
+		} while (select(fifos->server +1, NULL, &fds, NULL, NULL) != 1);
+
+		ret = write(fifos->server, msg, sizeof(*msg) - bytes);
+		bytes += ret > 0 ? ret : 0;
+	}
+
+	return bytes == sizeof(*msg);
+}
+
+/*
+ * Handle a client request.
+ *
+ * We put the request handling functions into
+ * a list because of the growing number.
+ */
+static int handle_request(struct dm_event_daemon_message *msg,
+			  struct message_data *message_data)
+{
+	static struct {
+		unsigned int cmd;
+		int (*f)(struct message_data*);
+	} requests[] = {
+		{ DM_EVENT_CMD_REGISTER_FOR_EVENT,         register_for_event },
+		{ DM_EVENT_CMD_UNREGISTER_FOR_EVENT,       unregister_for_event },
+		{ DM_EVENT_CMD_GET_REGISTERED_DEVICE,      get_registered_device },
+		{ DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE, get_next_registered_device },
+		{ DM_EVENT_CMD_SET_TIMEOUT,                set_timeout },
+		{ DM_EVENT_CMD_GET_TIMEOUT,                get_timeout },
+		{ DM_EVENT_CMD_ACTIVE,                     active },
+	}, *req;
+
+	for (req = requests; req < requests + sizeof(requests); req++) {
+		if (req->cmd == msg->opcode.cmd)
+			return req->f(message_data);
+	}
+
+	return -EINVAL;
+}
+
+/* Process a request passed from the communication thread. */
+static int do_process_request(struct dm_event_daemon_message *msg)
+{
+	int ret;
+	static struct message_data message_data;
+
+	/* Parse the message. */
+	memset(&message_data, 0, sizeof(message_data));
+	message_data.msg = msg;
+	if (msg->opcode.cmd != DM_EVENT_CMD_ACTIVE &&
+	    !parse_message(&message_data)) {
+		stack;
+		ret = -EINVAL;
+	} else {
+log_print("%s: %u \"%s\"\n", __func__, msg->opcode.cmd, message_data.msg->msg);
+		ret = handle_request(msg, &message_data);
+	}
+
+	free_message(&message_data);
+
+	return ret;
+}
+
+/* Only one caller at a time. */
+static void process_request(struct dm_event_fifos *fifos)
+{
+	struct dm_event_daemon_message msg;
+
+	/* FIXME: better error handling */
+
+	/* Read the request from the client. */
+	if (!memset(&msg, 0, sizeof(msg)) ||
+	    !client_read(fifos, &msg)) {
+		stack;
+		return;
+	}
+
+	msg.opcode.status = do_process_request(&msg);
+
+log_print("%s: status: %s\n", __func__, strerror(-msg.opcode.status));
+	if (!client_write(fifos, &msg))
+		stack;
+}
+
+static void sig_alarm(int signum)
+{
+	pthread_testcancel();
+}
+
+/* Init thread signal handling. */
+static void init_thread_signals(void)
+{
+	sigset_t sigset;
+	struct sigaction act;
+	
+	memset(&act, 0, sizeof(act));
+	act.sa_handler = sig_alarm;
+	sigaction(SIGALRM, &act, NULL);
+	sigfillset(&sigset);
+	pthread_sigmask(SIG_BLOCK, &sigset, NULL);
+}
+
+static int daemonize(void)
+{
+	setsid();
+	if (chdir("/"))
+		return -EXIT_CHDIR_FAILURE;
+
+/* FIXME: activate again after we're done with tracing.
+	if ((close(STDIN_FILENO) < 0) ||
+	    (close(STDOUT_FILENO) < 0) ||
+	    (close(STDERR_FILENO) < 0))
+		return -EXIT_DESC_CLOSE_FAILURE;
+*/
+
+	return 0;
+}
+
+static int lock_pidfile(void)
+{
+	int lf;
+	char pidfile[] = "/var/run/dmeventd.pid";
+
+	if ((lf = open(pidfile, O_CREAT | O_RDWR, 0644)) < 0)
+		return -EXIT_OPEN_PID_FAILURE;
+
+	if (flock(lf, LOCK_EX | LOCK_NB) < 0)
+		return -EXIT_LOCKFILE_INUSE;
+
+	if (!storepid(lf))
+		return -EXIT_FAILURE;
+
+	return 0;
+}
+
+void dmeventd(void)
+{
+	int ret;
+	struct dm_event_fifos fifos;
+	// struct sys_log logdata = {DAEMON_NAME, LOG_DAEMON};
+
+	if ((ret = daemonize()))
+		exit(-ret);
+
+	/* FIXME: set daemon name. */
+	// set_name();
+
+	if ((ret = lock_pidfile()))
+		exit(-ret);
+
+	init_thread_signals();
+
+	//multilog_clear_logging();
+	//multilog_add_type(std_syslog, &logdata);
+	//multilog_init_verbose(std_syslog, _LOG_DEBUG);
+	//multilog_async(1);
+
+	if ((ret = init_fifos(&fifos)))
+		exit(-ret);
+
+	pthread_mutex_init(&mutex, NULL);
+
+#ifdef MCL_CURRENT
+	if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1)
+		exit(EXIT_FAILURE);
+#endif
+
+	if ((ret = open_fifos(&fifos)))
+		exit(-ret);
+
+	/* Signal parent, letting them know we are ready to go. */
+	kill(getppid(), SIGUSR1);
+
+	/*
+	 * We exit when there are no more devices to watch.
+	 * That is, when the last unregister happens.
+	 */
+	do {
+		process_request(&fifos);
+	} while(!list_empty(&thread_registry));
+
+#ifdef MCL_CURRENT
+	munlockall();
+#endif
+	pthread_mutex_destroy(&mutex);
+
+	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:
+ */

Added: devmapper/trunk/dmeventd/dmeventd.h
==============================================================================
--- (empty file)
+++ devmapper/trunk/dmeventd/dmeventd.h	Fri Dec  2 18:59:40 2005
@@ -0,0 +1,12 @@
+#ifndef __DMEVENTD_DOT_H__
+#define __DMEVENTD_DOT_H__
+
+#define EXIT_LOCKFILE_INUSE      2
+#define EXIT_DESC_CLOSE_FAILURE  3
+#define EXIT_OPEN_PID_FAILURE    4
+#define EXIT_FIFO_FAILURE        5
+#define EXIT_CHDIR_FAILURE       6
+
+void dmeventd(void);
+
+#endif /* __DMEVENTD_DOT_H__ */

Added: devmapper/trunk/dmeventd/libdevmapper-event.c
==============================================================================
--- (empty file)
+++ devmapper/trunk/dmeventd/libdevmapper-event.c	Fri Dec  2 18:59:40 2005
@@ -0,0 +1,465 @@
+ /*
+ * 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 "lib.h"
+#include "libdevmapper-event.h"
+//#include "libmultilog.h"
+#include "dmeventd.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>
+#include <signal.h>
+#include <sys/wait.h>
+
+/* Set by any of the external fxns the first time one of them is called */
+/* FIXME Unused */
+// static int _logging = 0;
+
+/* Fetch a string off src and duplicate it into *dest. */
+/* FIXME: move to seperate module to share with the daemon. */
+static const char delimiter = ' ';
+static char *fetch_string(char **src)
+{
+	char *p, *ret;
+
+	if ((p = strchr(*src, delimiter)))
+		*p = 0;
+
+	if ((ret = strdup(*src)))
+		*src += strlen(ret) + 1;
+
+	if (p)
+		*p = delimiter;
+
+	return ret;
+}
+
+/* Parse a device message from the daemon. */
+static int parse_message(struct dm_event_daemon_message *msg, char **dso_name,
+			 char **device, enum dm_event_type *events)
+{
+	char *p = msg->msg;
+
+	if ((*dso_name = fetch_string(&p)) &&
+	    (*device   = fetch_string(&p))) {
+		*events = atoi(p);
+
+		return 0;
+	}
+
+	return -ENOMEM;
+}
+
+/* Read message from daemon. */
+static int daemon_read(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
+{
+	int bytes = 0, ret = 0;
+	fd_set fds;
+
+	memset(msg, 0, sizeof(*msg));
+	errno = 0;
+	/* FIXME Fix error handling. Check 'ret' before errno. EINTR? EAGAIN? */
+	/* FIXME errno != EOF?   RTFM! */
+	while (bytes < sizeof(*msg) && errno != EOF) {
+		do {
+			/* Watch daemon read FIFO for input. */
+			FD_ZERO(&fds);
+			FD_SET(fifos->server, &fds);
+		/* FIXME Check for errors e.g. EBADF */
+		} while (select(fifos->server+1, &fds, NULL, NULL, NULL) != 1);
+
+		ret = read(fifos->server, msg, sizeof(*msg) - bytes);
+		bytes += ret > 0 ? ret : 0;
+	}
+
+// log_print("%s: \"%s\"\n", __func__, msg->msg);
+	return bytes == sizeof(*msg);
+}
+
+/* Write message to daemon. */
+static int daemon_write(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
+{
+	int bytes = 0, ret = 0;
+	fd_set fds;
+
+
+// log_print("%s: \"%s\"\n", __func__, msg->msg);
+	errno = 0;
+	/* FIXME Fix error handling. Check 'ret' before errno. EINTR? EAGAIN? */
+	while (bytes < sizeof(*msg) && errno != EIO) {
+		do {
+			/* Watch daemon write FIFO to be ready for output. */
+			FD_ZERO(&fds);
+			FD_SET(fifos->client, &fds);
+		/* FIXME Check for errors e.g. EBADF */
+		} while (select(fifos->client +1, NULL, &fds, NULL, NULL) != 1);
+
+		ret = write(fifos->client, msg, sizeof(*msg) - bytes);
+		bytes += ret > 0 ? ret : 0;
+	}
+
+	return bytes == sizeof(*msg);
+}
+
+static int daemon_talk(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg,
+		       int cmd, char *dso_name, char *device,
+		       enum dm_event_type events, uint32_t timeout)
+{
+	memset(msg, 0, sizeof(*msg));
+
+	/*
+	 * Set command and pack the arguments
+	 * into ASCII message string.
+	 */
+	msg->opcode.cmd = cmd;
+
+	if (sizeof(msg->msg) <= snprintf(msg->msg, sizeof(msg->msg),
+					 "%s %s %u %"PRIu32,
+					 dso_name ? dso_name : "",
+					 device ? device : "",
+					 events, timeout)) {
+		stack;
+		return -ENAMETOOLONG;
+	}
+
+	/*
+	 * Write command and message to and
+	 * read status return code from daemon.
+	 */
+	if (!daemon_write(fifos, msg)) {
+		stack;
+		return -EIO;
+	}
+
+	if (!daemon_read(fifos, msg)) {
+		stack;
+		return -EIO;
+	}
+
+	return msg->opcode.status;
+}
+
+static volatile sig_atomic_t daemon_running = 0;
+
+static void daemon_running_signal_handler(int sig)
+{
+	daemon_running = 1;
+}
+
+/*
+ * start_daemon
+ *
+ * This function forks off a process (dmeventd) that will handle
+ * the events.  A signal must be returned from the child to
+ * indicate when it is ready to handle requests.  The parent
+ * (this function) returns 1 if there is a daemon running. 
+ *
+ * Returns: 1 on success, 0 otherwise
+ */
+static int start_daemon(void)
+{
+	int pid, ret=0;
+	int old_mask;
+	void *old_hand;
+
+	/* Must be able to acquire signal */
+	old_hand = signal(SIGUSR1, &daemon_running_signal_handler);
+	if (old_hand == SIG_ERR) {
+		log_error("Unable to setup signal handler.");
+		return 0;
+	}
+
+#ifdef linux
+	/* FIXME Deprecated. Try posix sigprocmask instead. */
+	old_mask = siggetmask();
+	old_mask &= ~sigmask(SIGUSR1);
+	old_mask = sigsetmask(old_mask);
+#endif
+	
+	pid = fork();
+
+	if (pid < 0)
+		log_error("Unable to fork.\n");
+	else if (pid) { /* parent waits for child to get ready for requests */
+		int status;
+
+		/* FIXME Better way to do this? */
+		while (!waitpid(pid, &status, WNOHANG) && !daemon_running)
+			sleep(1);
+
+		if (daemon_running) {
+			log_print("dmeventd started.\n");
+			ret = 1;
+		} else {
+			switch (WEXITSTATUS(status)) {
+			case EXIT_LOCKFILE_INUSE:
+				/*
+				 * Note, this is ok... we still have daemon
+				 * that we can communicate with...
+				 */
+				log_print("Starting dmeventd failed: "
+					  "dmeventd already running.\n");
+				ret = 1;
+				break;
+			default:
+				log_error("Unable to start dmeventd.\n");
+				break;
+			}
+		}
+	} else {
+		signal(SIGUSR1, SIG_IGN); /* don't care about error */
+
+		/* dmeventd function is responsible for properly setting **
+		** itself up.  It must never return - only exit.  This is**
+		** why it is followed by an EXIT_FAILURE                 */
+		dmeventd();
+		exit(EXIT_FAILURE);
+	}
+
+	/* FIXME What if old_hand is SIG_ERR? */
+	if (signal(SIGUSR1, old_hand) == SIG_ERR)
+		log_error("Unable to reset signal handler.");
+	sigsetmask(old_mask);
+
+        return ret;
+}
+
+/* Initialize client. */
+static int init_client(struct dm_event_fifos *fifos)
+{
+	/* FIXME Is fifo the most suitable method? */
+	/* FIXME Why not share comms/daemon code with something else e.g. multipath? */
+
+	/* init fifos */
+	memset(fifos, 0, sizeof(*fifos));
+        fifos->client_path = DM_EVENT_FIFO_CLIENT;
+        fifos->server_path = DM_EVENT_FIFO_SERVER;
+
+	/* FIXME The server should be responsible for these, not the client. */
+	/* Create fifos */
+	if (((mkfifo(fifos->client_path, 0600) == -1) && errno != EEXIST) ||
+	    ((mkfifo(fifos->server_path, 0600) == -1) && errno != EEXIST)) {
+		log_error("%s: Failed to create a fifo.\n", __func__);
+                return 0;
+	}
+
+	/* FIXME Warn/abort if perms are wrong - not something to fix silently. */
+	/* If they were already there, make sure permissions are ok. */
+	if (chmod(fifos->client_path, 0600)) {
+		log_error("Unable to set correct file permissions on %s",
+			fifos->client_path);
+		return 0;
+	}
+
+	if (chmod(fifos->server_path, 0600)) {
+		log_error("Unable to set correct file permissions on %s",
+			fifos->server_path);
+		return 0;
+	}
+
+	/*
+	 * Open the fifo used to read from the daemon.
+	 * Allows daemon to create its write fifo...
+	 */
+	if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
+		log_error("%s: open server fifo %s\n",
+			__func__, fifos->server_path);
+		stack;
+		return 0;
+	}
+
+	/* Lock out anyone else trying to do communication with the daemon. */
+	/* FIXME Why failure not retry?  How do multiple processes communicate? */
+	if (flock(fifos->server, LOCK_EX) < 0){
+		log_error("%s: flock %s\n", __func__, fifos->server_path);
+		close(fifos->server);
+		return 0;
+	}
+
+	/* Anyone listening?  If not, errno will be ENXIO */
+	if ((fifos->client = open(fifos->client_path,
+				  O_WRONLY | O_NONBLOCK)) < 0) {
+		if (errno != ENXIO) {
+			log_error("%s: open client fifo %s\n",
+				__func__, fifos->client_path);
+			close(fifos->server);
+			stack;
+			return 0;
+		}
+		
+		/* FIXME Unnecessary if daemon was started before calling this */
+		if (!start_daemon()) {
+			stack;
+			return 0;
+		}
+
+		/* FIXME Unnecessary if daemon was started before calling this */
+		/* Daemon is started, retry the open */
+		fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK);
+		if (fifos->client < 0) {
+			log_error("%s: open client fifo %s\n",
+				__func__, fifos->client_path);
+			close(fifos->server);
+			stack;
+			return 0;
+		}
+	}
+	
+	return 1;
+}
+
+static void dtr_client(struct dm_event_fifos *fifos)
+{
+	if (flock(fifos->server, LOCK_UN))
+                log_error("flock unlock %s\n", fifos->server_path);
+
+	close(fifos->client);
+	close(fifos->server);
+}
+
+/* Check, if a block device exists. */
+static int device_exists(char *device)
+{
+	struct stat st_buf;
+	char path2[PATH_MAX];
+
+	if (!device)
+		return 0;
+
+	if (device[0] == '/') /* absolute path */
+		return !stat(device, &st_buf) && S_ISBLK(st_buf.st_mode);
+
+	if (PATH_MAX <= snprintf(path2, PATH_MAX, "%s/%s", dm_dir(), device))
+		return 0;
+
+	return !stat(path2, &st_buf) && S_ISBLK(st_buf.st_mode);
+}
+
+/* Handle the event (de)registration call and return negative error codes. */
+static int do_event(int cmd, struct dm_event_daemon_message *msg,
+		    char *dso_name, char *device, enum dm_event_type events,
+		    uint32_t timeout)
+{
+	int ret;
+	struct dm_event_fifos fifos;
+
+	/* FIXME Start the daemon here if it's not running e.g. exclusive lock file */
+
+	if (!init_client(&fifos)) {
+		stack;
+		return -ESRCH;
+	}
+
+	ret = daemon_talk(&fifos, msg, cmd, dso_name, device, events, timeout);
+
+	/* what is the opposite of init? */
+	dtr_client(&fifos);
+	
+	return ret;
+}
+
+/* External library interface. */
+int dm_event_register(char *dso_name, char *device_path,
+			  enum dm_event_type events)
+{
+	struct dm_event_daemon_message msg;
+
+	if (!device_exists(device_path))
+		return -ENODEV;
+
+	return do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
+			dso_name, device_path, events, 0);
+}
+
+int dm_event_unregister(char *dso_name, char *device_path,
+			    enum dm_event_type events)
+{
+	struct dm_event_daemon_message msg;
+
+	if (!device_exists(device_path))
+		return -ENODEV;
+
+	return do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
+			dso_name, device_path, events, 0);
+}
+
+int dm_event_get_registered_device(char **dso_name, char **device_path,
+			     enum dm_event_type *events, int next)
+{
+	int ret;
+	char *dso_name_arg = NULL, *device_path_arg = NULL;
+	struct dm_event_daemon_message msg;
+
+	if (!(ret = do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
+				    DM_EVENT_CMD_GET_REGISTERED_DEVICE,
+			     &msg, *dso_name, *device_path, *events, 0)))
+		ret = parse_message(&msg, &dso_name_arg, &device_path_arg,
+				    events);
+
+	if (next){
+		if (*dso_name)
+			free(*dso_name);
+		if (*device_path)
+			free(*device_path);
+		*dso_name = dso_name_arg;
+		*device_path = device_path_arg;
+	} else {
+		if (!(*dso_name))
+			*dso_name = dso_name_arg;
+		if (!(*device_path))
+			*device_path = device_path_arg;
+	}
+
+	return ret;
+}
+
+int dm_event_set_timeout(char *device_path, uint32_t timeout)
+{
+	struct dm_event_daemon_message msg;
+
+	if (!device_exists(device_path))
+		return -ENODEV;
+	return do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg,
+			NULL, device_path, 0, timeout);
+}
+
+int dm_event_get_timeout(char *device_path, uint32_t *timeout)
+{
+	int ret;
+	struct dm_event_daemon_message msg;
+
+	if (!device_exists(device_path))
+		return -ENODEV;
+	if (!(ret = do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path, 0, 0)))
+		*timeout = atoi(msg.msg);
+	return ret;
+}
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */

Added: devmapper/trunk/dmeventd/libdevmapper-event.h
==============================================================================
--- (empty file)
+++ devmapper/trunk/dmeventd/libdevmapper-event.h	Fri Dec  2 18:59:40 2005
@@ -0,0 +1,99 @@
+/*
+ * 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
+ */
+
+/*
+ * Note that this file is released only as part of a technology preview
+ * and its contents may change in future updates in ways that do not
+ * preserve compatibility.
+ */
+
+#ifndef LIB_DMEVENT_H
+#define LIB_DMEVENT_H
+
+#include <stdint.h>
+
+/* FIXME This stuff must be configurable. */
+
+#define	DM_EVENT_DAEMON		"/sbin/dmeventd"
+#define DM_EVENT_LOCKFILE	"/var/lock/dmeventd"
+#define	DM_EVENT_FIFO_CLIENT	"/var/run/dmeventd-client"
+#define	DM_EVENT_FIFO_SERVER	"/var/run/dmeventd-server"
+#define DM_EVENT_PIDFILE	"/var/run/dmeventd.pid"
+
+#define DM_EVENT_DEFAULT_TIMEOUT 10
+
+/* Commands for the daemon passed in the message below. */
+enum dm_event_command {
+	DM_EVENT_CMD_ACTIVE = 1,
+	DM_EVENT_CMD_REGISTER_FOR_EVENT,
+	DM_EVENT_CMD_UNREGISTER_FOR_EVENT,
+	DM_EVENT_CMD_GET_REGISTERED_DEVICE,
+	DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
+	DM_EVENT_CMD_SET_TIMEOUT,
+	DM_EVENT_CMD_GET_TIMEOUT,
+};
+
+/* Message passed between client and daemon. */
+struct dm_event_daemon_message {
+	union {
+		unsigned int cmd;	/* FIXME Use fixed size. */
+		int	 status;	/* FIXME Use fixed size. */
+	} opcode;
+	char msg[252];		/* FIXME Why is this 252 ? */
+} __attribute__((packed));	/* FIXME Do this properly! */
+
+/* FIXME Is this meant to be exported?  I can't see where the interface uses it. */
+/* Fifos for client/daemon communication. */
+struct dm_event_fifos {
+	int client;
+	int server;
+	const char *client_path;
+	const char *server_path;
+};
+
+/* Event type definitions. */
+/* FIXME Use masks to separate the types and provide for extension. */
+enum dm_event_type {
+	DM_EVENT_SINGLE		= 0x01, /* Report multiple errors just once. */
+	DM_EVENT_MULTI		= 0x02, /* Report all of them. */
+
+	DM_EVENT_SECTOR_ERROR	= 0x04, /* Failure on a particular sector. */
+	DM_EVENT_DEVICE_ERROR	= 0x08, /* Device failure. */
+	DM_EVENT_PATH_ERROR	= 0x10, /* Failure on an io path. */
+	DM_EVENT_ADAPTOR_ERROR	= 0x20, /* Failure off a host adaptor. */
+
+	DM_EVENT_SYNC_STATUS	= 0x40, /* Mirror synchronization completed/failed. */
+	DM_EVENT_TIMEOUT	= 0x80, /* Timeout has occured */
+};
+
+/* FIXME Use a mask. */
+#define	DM_EVENT_ALL_ERRORS (DM_EVENT_SECTOR_ERROR | DM_EVENT_DEVICE_ERROR | \
+			     DM_EVENT_PATH_ERROR | DM_EVENT_ADAPTOR_ERROR)
+
+/* Prototypes for event lib interface. */
+/* FIXME Missing consts? */
+int dm_event_register(char *dso_name, char *device, enum dm_event_type events);
+int dm_event_unregister(char *dso_name, char *device,
+			enum dm_event_type events);
+int dm_event_get_registered_device(char **dso_name, char **device,
+				   enum dm_event_type *events, int next);
+int dm_event_set_timeout(char *device, uint32_t timeout);
+int dm_event_get_timeout(char *device, uint32_t *timeout);
+
+/* Prototypes for DSO interface. */
+void process_event(const char *device, enum dm_event_type event);
+int register_device(const char *device);
+int unregister_device(const char *device);
+
+#endif

Modified: devmapper/trunk/include/.symlinks
==============================================================================
--- devmapper/trunk/include/.symlinks	(original)
+++ devmapper/trunk/include/.symlinks	Fri Dec  2 18:59:40 2005
@@ -1,3 +1,4 @@
 ../lib/libdevmapper.h
 ../lib/libdm-file.h
+../dmeventd/libdevmapper-event.h
 ../po/pogen.h

Modified: devmapper/trunk/lib/.exported_symbols
==============================================================================
--- devmapper/trunk/lib/.exported_symbols	(original)
+++ devmapper/trunk/lib/.exported_symbols	Fri Dec  2 18:59:40 2005
@@ -22,9 +22,11 @@
 dm_task_set_minor
 dm_task_set_sector
 dm_task_set_message
+dm_task_suppress_identical_reload
 dm_task_add_target
 dm_task_no_open_count
 dm_task_skip_lockfs
+dm_task_update_nodes
 dm_task_run
 dm_get_next_target
 dm_set_dev_dir
@@ -61,11 +63,12 @@
 dm_is_dm_major
 dm_mknodes
 dm_malloc_aux
+dm_malloc_aux_debug
 dm_strdup
 dm_free_aux
 dm_realloc_aux
-dm_dump_memory
-dm_bounds_check
+dm_dump_memory_debug
+dm_bounds_check_debug
 dm_pool_create
 dm_pool_destroy
 dm_pool_alloc

Modified: devmapper/trunk/lib/ioctl/libdm-iface.c
==============================================================================
--- devmapper/trunk/lib/ioctl/libdm-iface.c	(original)
+++ devmapper/trunk/lib/ioctl/libdm-iface.c	Fri Dec  2 18:59:40 2005
@@ -672,11 +672,13 @@
 #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));
+			log_verbose("device-mapper: %s ioctl failed: %s", 
+				    _cmd_data_v1[dmt->type].name,
+				    strerror(errno));
 		else
-			log_error("device-mapper ioctl cmd %d failed: %s",
-				  _IOC_NR(command), strerror(errno));
+			log_error("device-mapper: %s ioctl failed: %s",
+				  _cmd_data_v1[dmt->type].name,
+				  strerror(errno));
 		goto bad;
 	}
 #else /* Userspace alternative for testing */
@@ -875,7 +877,7 @@
 	if (bufsize < 8)
 		return 0;
 
-	r = snprintf(buf, bufsize, "%03u:%03u", dev_major, dev_minor);
+	r = snprintf(buf, bufsize, "%u:%u", dev_major, dev_minor);
 	if (r < 0 || r > bufsize - 1)
 		return 0;
 
@@ -966,6 +968,12 @@
 	return 1;
 }
 
+int dm_task_suppress_identical_reload(struct dm_task *dmt)
+{
+	dmt->suppress_identical_reload = 1;
+	return 1;
+}
+
 int dm_task_set_newname(struct dm_task *dmt, const char *newname)
 {
 	if (!(dmt->newname = dm_strdup(newname))) {
@@ -1342,6 +1350,71 @@
 	return r;
 }
 
+static int _reload_with_suppression_v4(struct dm_task *dmt)
+{
+	struct dm_task *task;
+	struct target *t1, *t2;
+	int matches = 1;
+	int r;
+
+	/* New task to get existing table information */
+	if (!(task = dm_task_create(DM_DEVICE_TABLE))) {
+		log_error("Failed to create device-mapper task struct");
+		return 0;
+	}
+
+	/* Copy across relevant fields */
+	if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name)) {
+		dm_task_destroy(task);
+		return 0;
+	}
+
+	if (dmt->uuid && !dm_task_set_uuid(task, dmt->uuid)) {
+		dm_task_destroy(task);
+		return 0;
+	}
+
+	task->major = dmt->major;
+	task->minor = dmt->minor;
+
+	r = dm_task_run(task);
+
+	if (!r) {
+		dm_task_destroy(task);
+		return r;
+	}
+
+	t1 = dmt->head;
+	t2 = task->head;
+
+	while (t1 && t2) {
+		if ((t1->start != t2->start) ||
+		    (t1->length != t2->length) ||
+		    (strcmp(t1->type, t2->type)) ||
+		    (strcmp(t1->params, t2->params))) {
+			matches = 0;
+			break;
+		}
+		t1 = t1->next;
+		t2 = t2->next;
+	}
+	
+	if (matches && !t1 && !t2) {
+		dmt->dmi.v4 = task->dmi.v4;
+		task->dmi.v4 = NULL;
+		dm_task_destroy(task);
+		return 1;
+	}
+
+	dm_task_destroy(task);
+
+	/* Now do the original reload */
+	dmt->suppress_identical_reload = 0;
+	r = dm_task_run(dmt);
+
+	return r;
+}
+
 static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
 				     unsigned repeat_count)
 {
@@ -1383,13 +1456,15 @@
 			dmi->flags &= ~DM_EXISTS_FLAG;	/* FIXME */
 		else {
 			if (_log_suppress)
-				log_verbose("device-mapper ioctl "
-					    "cmd %d failed: %s",
-					    _IOC_NR(command), strerror(errno));
+				log_verbose("device-mapper: %s ioctl "
+					    "failed: %s",
+				    	    _cmd_data_v4[dmt->type].name,
+					    strerror(errno));
 			else
-				log_error("device-mapper ioctl "
-					  "cmd %d failed: %s",
-					  _IOC_NR(command), strerror(errno));
+				log_error("device-mapper: %s ioctl "
+					  "failed: %s",
+				    	   _cmd_data_v4[dmt->type].name,
+					  strerror(errno));
 			dm_free(dmi);
 			return NULL;
 		}
@@ -1399,6 +1474,11 @@
 	return dmi;
 }
 
+void dm_task_update_nodes(void)
+{
+	update_devs();
+}
+
 int dm_task_run(struct dm_task *dmt)
 {
 	struct dm_ioctl *dmi;
@@ -1426,6 +1506,9 @@
 	    !dmt->uuid && dmt->major <= 0)
 		return _mknodes_v4(dmt);
 
+	if ((dmt->type == DM_DEVICE_RELOAD) && dmt->suppress_identical_reload)
+		return _reload_with_suppression_v4(dmt);
+
 	if (!_open_control())
 		return 0;
 

Modified: devmapper/trunk/lib/ioctl/libdm-targets.h
==============================================================================
--- devmapper/trunk/lib/ioctl/libdm-targets.h	(original)
+++ devmapper/trunk/lib/ioctl/libdm-targets.h	Fri Dec  2 18:59:40 2005
@@ -53,6 +53,7 @@
 	uint64_t sector;
 	int no_open_count;
 	int skip_lockfs;
+	int suppress_identical_reload;
 
 	char *uuid;
 };

Modified: devmapper/trunk/lib/libdevmapper.h
==============================================================================
--- devmapper/trunk/lib/libdevmapper.h	(original)
+++ devmapper/trunk/lib/libdevmapper.h	Fri Dec  2 18:59:40 2005
@@ -145,6 +145,7 @@
 int dm_task_set_sector(struct dm_task *dmt, uint64_t sector);
 int dm_task_no_open_count(struct dm_task *dmt);
 int dm_task_skip_lockfs(struct dm_task *dmt);
+int dm_task_suppress_identical_reload(struct dm_task *dmt);
 
 /*
  * Use these to prepare for a create or reload.
@@ -169,6 +170,12 @@
 int dm_task_run(struct dm_task *dmt);
 
 /*
+ * Call this to make or remove the device nodes associated with previously
+ * issued commands.
+ */
+void dm_task_update_nodes(void);
+
+/*
  * Configure the device-mapper directory
  */
 int dm_set_dev_dir(const char *dir);
@@ -342,30 +349,34 @@
  * Memory management
  *******************/
 
-void *dm_malloc_aux(size_t s, const char *file, int line);
-#define dm_malloc(s) dm_malloc_aux((s), __FILE__, __LINE__)
-
 char *dm_strdup(const char *str);
 
-#ifdef DEBUG_MEM
-
+void *dm_malloc_aux(size_t s, const char *file, int line);
+void *dm_malloc_aux_debug(size_t s, const char *file, int line);
 void dm_free_aux(void *p);
 void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line);
-int dm_dump_memory(void);
-void dm_bounds_check(void);
+int dm_dump_memory_debug(void);
+void dm_bounds_check_debug(void);
 
+#ifdef DEBUG_MEM
+
+#  define dm_malloc(s) dm_malloc_aux_debug((s), __FILE__, __LINE__)
 #  define dm_free(p) dm_free_aux(p)
 #  define dm_realloc(p, s) dm_realloc_aux(p, s, __FILE__, __LINE__)
+#  define dm_dump_memory() dm_dump_memory_debug()
+#  define dm_bounds_check() dm_bounds_check_debug()
 
 #else
 
+#  define dm_malloc(s) dm_malloc_aux((s), __FILE__, __LINE__)
 #  define dm_free(p) free(p)
 #  define dm_realloc(p, s) realloc(p, s)
-#  define dm_dump_memory()
-#  define dm_bounds_check()
+#  define dm_dump_memory() {}
+#  define dm_bounds_check() {}
 
 #endif
 
+
 /*
  * The pool allocator is useful when you are going to allocate
  * lots of memory, use the memory for a bit, and then free the

Modified: devmapper/trunk/lib/libdm-deptree.c
==============================================================================
--- devmapper/trunk/lib/libdm-deptree.c	(original)
+++ devmapper/trunk/lib/libdm-deptree.c	Fri Dec  2 18:59:40 2005
@@ -25,6 +25,9 @@
 
 #define MAX_TARGET_PARAMSIZE 500000
 
+/* FIXME Fix interface so this is used only by LVM */
+#define UUID_PREFIX "LVM-"
+
 /* Supported segment types */
 enum {
 	SEG_ERROR, 
@@ -112,6 +115,8 @@
         struct list uses;       	/* Nodes this node uses */
         struct list used_by;    	/* Nodes that use this node */
 
+	int activation_priority;	/* 0 gets activated first */
+
 	void *context;			/* External supplied context */
 
 	struct load_properties props;	/* For creation/table (re)load */
@@ -310,6 +315,7 @@
 	node->uuid = uuid;
 	node->info = *info;
 	node->context = context;
+	node->activation_priority = 0;
 
 	list_init(&node->uses);
 	list_init(&node->used_by);
@@ -348,8 +354,15 @@
 static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,
 						       const char *uuid)
 {
-	/* FIXME Do we need to cope with missing LVM- prefix too? */
-	return dm_hash_lookup(dtree->uuids, uuid);
+	struct dm_tree_node *node;
+
+	if ((node = dm_hash_lookup(dtree->uuids, uuid)))
+		return node;
+
+	if (strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
+		return NULL;
+
+	return dm_hash_lookup(dtree->uuids, uuid + sizeof(UUID_PREFIX) - 1);
 }
 
 static int _deps(struct dm_task **dmt, struct dm_pool *mem, uint32_t major, uint32_t minor,
@@ -653,13 +666,13 @@
 	if (uuid_prefix_len <= 4)
 		return 0;
 
-	if (!strncmp(uuid, "LVM-", 4))
+	if (!strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
 		return 0;
 
-	if (strncmp(uuid_prefix, "LVM-", 4))
+	if (strncmp(uuid_prefix, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))
 		return 0;
 
-	if (!strncmp(uuid, uuid_prefix + 4, uuid_prefix_len - 4))
+	if (!strncmp(uuid, uuid_prefix + sizeof(UUID_PREFIX) - 1, uuid_prefix_len - (sizeof(UUID_PREFIX) - 1)))
 		return 1;
 
 	return 0;
@@ -1026,7 +1039,7 @@
 		}
 
 		/* Ignore if it doesn't belong to this VG */
-		if (uuid_prefix && strncmp(uuid, uuid_prefix, uuid_prefix_len))
+		if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
 			continue;
 
 		if (dm_tree_node_num_children(child, 0))
@@ -1045,6 +1058,7 @@
 	struct dm_info newinfo;
 	const char *name;
 	const char *uuid;
+	int priority;
 
 	/* Activate children first */
 	while ((child = dm_tree_next_child(&handle, dnode, 0))) {
@@ -1058,36 +1072,53 @@
 
 		if (dm_tree_node_num_children(child, 0))
 			dm_tree_activate_children(child, uuid_prefix, uuid_prefix_len);
+	}
 
-		if (!(name = dm_tree_node_get_name(child))) {
-			stack;
-			continue;
-		}
+	handle = NULL;
 
-		/* Rename? */
-		if (child->props.new_name) {
-			if (!_rename_node(name, child->props.new_name, child->info.major, child->info.minor)) {
-				log_error("Failed to rename %s (%" PRIu32
-					  ":%" PRIu32 ") to %s", name, child->info.major,
-					  child->info.minor, child->props.new_name);
-				return 0;
+	for (priority = 0; priority < 2; priority++) {
+		while ((child = dm_tree_next_child(&handle, dnode, 0))) {
+			if (!(uuid = dm_tree_node_get_uuid(child))) {
+				stack;
+				continue;
 			}
-			child->name = child->props.new_name;
-			child->props.new_name = NULL;
-		}
 
-		if (!child->info.inactive_table && !child->info.suspended)
-			continue;
+			if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
+				continue;
 
-		if (!_resume_node(name, child->info.major, child->info.minor, &newinfo)) {
-			log_error("Unable to resume %s (%" PRIu32
-				  ":%" PRIu32 ")", name, child->info.major,
-				  child->info.minor);
-			continue;
-		}
+			if (priority != child->activation_priority)
+				continue;
 
-		/* Update cached info */
-		child->info = newinfo;
+			if (!(name = dm_tree_node_get_name(child))) {
+				stack;
+				continue;
+			}
+
+			/* Rename? */
+			if (child->props.new_name) {
+				if (!_rename_node(name, child->props.new_name, child->info.major, child->info.minor)) {
+					log_error("Failed to rename %s (%" PRIu32
+						  ":%" PRIu32 ") to %s", name, child->info.major,
+						  child->info.minor, child->props.new_name);
+					return 0;
+				}
+				child->name = child->props.new_name;
+				child->props.new_name = NULL;
+			}
+
+			if (!child->info.inactive_table && !child->info.suspended)
+				continue;
+
+			if (!_resume_node(name, child->info.major, child->info.minor, &newinfo)) {
+				log_error("Unable to resume %s (%" PRIu32
+					  ":%" PRIu32 ")", name, child->info.major,
+					  child->info.minor);
+				continue;
+			}
+
+			/* Update cached info */
+			child->info = newinfo;
+		}
 	}
 
 	handle = NULL;
@@ -1343,8 +1374,15 @@
 		if (!_emit_segment(dmt, seg, &seg_start))
 			goto_out;
 
-	if ((r = dm_task_run(dmt)))
+	if (!dm_task_suppress_identical_reload(dmt))
+		log_error("Failed to suppress reload of identical tables.");
+
+	if ((r = dm_task_run(dmt))) {
 		r = dm_task_get_info(dmt, &dnode->info);
+		if (r && !dnode->info.inactive_table)
+			log_verbose("Suppressed %s identical table reload.",
+				    dnode->name);
+	}
 
 	dnode->props.segment_count = 0;
 
@@ -1352,7 +1390,6 @@
 	dm_task_destroy(dmt);
 
 	return r;
-
 }
 
 int dm_tree_preload_children(struct dm_tree_node *dnode,
@@ -1371,8 +1408,8 @@
 			continue;
 
 		/* Ignore if it doesn't belong to this VG */
-		if (uuid_prefix && child->info.exists &&
-		    strncmp(child->uuid, uuid_prefix, uuid_prefix_len))
+		if (child->info.exists &&
+		    !_uuid_prefix_matches(child->uuid, uuid_prefix, uuid_prefix_len))
 			continue;
 
 		if (dm_tree_node_num_children(child, 0))
@@ -1402,6 +1439,9 @@
 		if (!dm_tree_node_num_children(child, 1))
 			continue;
 
+		if (!child->info.inactive_table && !child->info.suspended)
+			continue;
+
 		if (!_resume_node(name, child->info.major, child->info.minor, &newinfo)) {
 			log_error("Unable to resume %s (%" PRIu32
 				  ":%" PRIu32 ")", name, child->info.major,
@@ -1435,7 +1475,7 @@
 			return 1;
 		}
 
-		if (!strncmp(uuid, uuid_prefix, uuid_prefix_len))
+		if (_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
 			return 1;
 
 		if (dm_tree_node_num_children(child, 0))
@@ -1492,6 +1532,9 @@
 	if (!_link_tree_nodes(dnode, origin_node))
 		return_0;
 
+	/* Resume snapshot origins after new snapshots */
+	dnode->activation_priority = 1;
+
 	return 1;
 }
 

Modified: devmapper/trunk/lib/mm/dbg_malloc.c
==============================================================================
--- devmapper/trunk/lib/mm/dbg_malloc.c	(original)
+++ devmapper/trunk/lib/mm/dbg_malloc.c	Fri Dec  2 18:59:40 2005
@@ -28,8 +28,6 @@
 	return ret;
 }
 
-#ifdef DEBUG_MEM
-
 struct memblock {
 	struct memblock *prev, *next;	/* All allocated blocks are linked */
 	size_t length;		/* Size of the requested block */
@@ -51,7 +49,7 @@
 static struct memblock *_head = 0;
 static struct memblock *_tail = 0;
 
-void *dm_malloc_aux(size_t s, const char *file, int line)
+void *dm_malloc_aux_debug(size_t s, const char *file, int line)
 {
 	struct memblock *nb;
 	size_t tsize = s + sizeof(*nb) + sizeof(unsigned long);
@@ -72,9 +70,7 @@
 	nb->file = file;
 	nb->line = line;
 
-#ifdef BOUNDS_CHECK
 	dm_bounds_check();
-#endif
 
 	/* setup fields */
 	nb->magic = nb + 1;
@@ -125,9 +121,7 @@
 	if (!p)
 		return;
 
-#ifdef BOUNDS_CHECK
 	dm_bounds_check();
-#endif
 
 	/* sanity check */
 	assert(mb->magic == p);
@@ -171,7 +165,7 @@
 	void *r;
 	struct memblock *mb = ((struct memblock *) p) - 1;
 
-	r = dm_malloc_aux(s, file, line);
+	r = dm_malloc_aux_debug(s, file, line);
 
 	if (p) {
 		memcpy(r, p, mb->length);
@@ -181,7 +175,7 @@
 	return r;
 }
 
-int dm_dump_memory(void)
+int dm_dump_memory_debug(void)
 {
 	unsigned long tot = 0;
 	struct memblock *mb;
@@ -216,7 +210,7 @@
 	return 1;
 }
 
-void dm_bounds_check(void)
+void dm_bounds_check_debug(void)
 {
 	struct memblock *mb = _head;
 	while (mb) {
@@ -230,8 +224,6 @@
 	}
 }
 
-#else
-
 void *dm_malloc_aux(size_t s, const char *file, int line)
 {
 	if (s > 50000000) {
@@ -242,5 +234,3 @@
 
 	return malloc(s);
 }
-
-#endif



More information about the pkg-lvm-commits mailing list