<div>Is there any command-line example to explain how to use this  patch?</div>
<div>I have compiled it and loaded the modules, the '<start><length>' target parameters in both replicator ant replicator-dev targets means what?</div>
<div>how can I construct these target?</div>
<div>I haven't read the source code in detail till now, sorry. <br><br></div>
<div class="gmail_quote">2009/12/18 <span dir="ltr"><<a href="mailto:heinzm@redhat.com">heinzm@redhat.com</a>></span><br>
<blockquote class="gmail_quote" style="PADDING-LEFT: 1ex; MARGIN: 0px 0px 0px 0.8ex; BORDER-LEFT: #ccc 1px solid">From: Heinz Mauelshagen <<a href="mailto:heinzm@redhat.com">heinzm@redhat.com</a>><br><br>The dm-registry module is a general purpose registry for modules.<br>
<br>The remote replicator utilizes it to register its ringbuffer log and<br>site link handlers in order to avoid duplicating registry code and logic.<br><br><br>Signed-off-by: Heinz Mauelshagen <<a href="mailto:heinzm@redhat.com">heinzm@redhat.com</a>><br>
Reviewed-by: Jon Brassow <<a href="mailto:jbrassow@redhat.com">jbrassow@redhat.com</a>><br>Tested-by: Jon Brassow <<a href="mailto:jbrassow@redhat.com">jbrassow@redhat.com</a>><br>---<br> Documentation/device-mapper/replicator.txt |  203 +++++++++++++++++++++++++<br>
 drivers/md/Kconfig                         |    8 +<br> drivers/md/Makefile                        |    1 +<br> drivers/md/dm-registry.c                   |  224 ++++++++++++++++++++++++++++<br> drivers/md/dm-registry.h                   |   38 +++++<br>
 5 files changed, 474 insertions(+), 0 deletions(-)<br> create mode 100644 Documentation/device-mapper/replicator.txt<br> create mode 100644 drivers/md/dm-registry.c<br> create mode 100644 drivers/md/dm-registry.h<br><br>
diff --git 2.6.33-rc1.orig/Documentation/device-mapper/replicator.txt 2.6.33-rc1/Documentation/device-mapper/replicator.txt<br>new file mode 100644<br>index 0000000..1d408a6<br>--- /dev/null<br>+++ 2.6.33-rc1/Documentation/device-mapper/replicator.txt<br>
@@ -0,0 +1,203 @@<br>+dm-replicator<br>+=============<br>+<br>+Device-mapper replicator is designed to enable redundant copies of<br>+storage devices to be made - preferentially, to remote locations.<br>+RAID1 (aka mirroring) is often used to maintain redundant copies of<br>
+storage for fault tolerance purposes.  Unlike RAID1, which often<br>+assumes similar device characteristics, dm-replicator is designed to<br>+handle devices with different latency and bandwidth characteristics<br>+which are often the result of the geograhic disparity of multi-site<br>
+architectures.  Simply put, you might choose RAID1 to protect from<br>+a single device failure, but you would choose remote replication<br>+via dm-replicator for protection against a site failure.<br>+<br>+dm-replicator works by first sending write requests to the "replicator<br>
+log".  Not to be confused with the device-mapper dirty log, this<br>+replicator log behaves similarly to that of a journal.  Write requests<br>+go to this log first and then are copied to all the replicate devices<br>
+at their various locations.  Requests are cleared from the log once all<br>+replicate devices confirm the data is received/copied.  This architecture<br>+allows dm-replicator to be flexible in terms of device characteristics.<br>
+If one device should fall behind the others - perhaps due to high latency -<br>+the slack is picked up by the log.  The user has a great deal of<br>+flexibility in specifying to what degree a particular site is allowed to<br>
+fall behind - if at all.<br>+<br>+Device-Mapper's dm-replicator has two targets, "replicator" and<br>+"replicator-dev".  The "replicator" target is used to setup the<br>+aforementioned log and allow the specification of site link properties.<br>
+Through the "replicator" target, the user might specify that writes<br>+that are copied to the local site must happen synchronously (i.e the<br>+writes are complete only after they have passed through the log device<br>
+and have landed on the local site's disk).  They may also specify that<br>+a remote link should asynchronously complete writes, but that the remote<br>+link should never fall more than 100MB behind in terms of processing.<br>
+Again, the "replicator" target is used to define the replicator log and<br>+the characteristics of each site link.<br>+<br>+The "replicator-dev" target is used to define the devices used and<br>+associate them with a particular replicator log.  You might think of<br>
+this stage in a similar way to setting up RAID1 (mirroring).  You<br>+define a set of devices which will be copies of each other, but<br>+access the device through the mirror virtual device which takes care<br>+of the copying.  The user accessible replicator device is analogous<br>
+to the mirror virtual device, while the set of devices being copied<br>+to are analogous to the mirror images (sometimes called 'legs').<br>+When creating a replicator device via the "replicator-dev" target,<br>
+it must be associated with the replicator log (created with the<br>+aforementioned "replicator" target).  When each redundant device<br>+is specified as part of the replicator device, it is associated with<br>+a site link whose properties were defined when the "replicator"<br>
+target was created.<br>+<br>+The user can go farther than simply replicating one device.  They<br>+can continue to add replicator devices - associating them with a<br>+particular replicator log.  Writes that go through the replicator<br>
+log are guarenteed to have their write ordering preserved.  So, if<br>+you associate more than one replicator device to a particular<br>+replicator log, you are preserving write ordering across multiple<br>+devices.  This might be useful if you had a database that spanned<br>
+multiple disks and write ordering must be preserved or any transaction<br>+accounting scheme would be foiled.  (You can imagine this like<br>+preserving write ordering across a number of mirrored devices, where<br>+each mirror has images/legs in different geographic locations.)<br>
+<br>+dm-replicator has a modular architecture.  Future implementations for<br>+the replicator log and site link modules are allowed.  The current<br>+replication log is ringbuffer - utilized to store all writes being<br>
+subject to replication and enforce write ordering.  The current site<br>+link code is based on accessing block devices (iSCSI, FC, etc) and<br>+does device recovery including (initial) resynchronization.<br>+<br>+<br>+Picture of a 2 site configuration with 3 local devices (LDs) in a<br>
+primary site being resycnhronied to 3 remotes sites with 3 remote<br>+devices (RDs) each via site links (SLINK) 1-2 with site link 0<br>+as a special case to handle the local devices:<br>+<br>+                                           |<br>
+    Local (primary) site                   |      Remote sites<br>+    --------------------                   |      ------------<br>+                                           |<br>+    D1   D2     Dn                         |<br>
+     |   |       |                         |<br>+     +---+- ... -+                         |<br>+         |                                 |<br>+       REPLOG-----------------+- SLINK1 ------------+<br>+         |                    |            |        |<br>
+       SLINK0 (special case)  |            |        |<br>+         |                    |            |        |<br>+     +-----+   ...  +         |            |   +----+- ... -+<br>+     |     |        |         |            |   |    |       |<br>
+    LD1   LD2      LDn        |            |  RD1  RD2     RDn<br>+                              |            |<br>+                              +-- SLINK2------------+<br>+                              |            |        |<br>
+                              |            |   +----+- ... -+<br>+                              |            |   |    |       |<br>+                              |            |  RD1  RD2     RDn<br>+                              |            |<br>
+                              |            |<br>+                              |            |<br>+                              +- SLINKm ------------+<br>+                                           |        |<br>+                                           |   +----+- ... -+<br>
+                                           |   |    |       |<br>+                                           |  RD1  RD2     RDn<br>+<br>+<br>+<br>+<br>+The following are descriptions of the device-mapper tables used to<br>
+construct the "replicator" and "replicator-dev" targets.<br>+<br>+"replicator" target parameters:<br>+-------------------------------<br>+<start> <length> replicator \<br>+       <replog_type> <#replog_params> <replog_params> \<br>
+       [<slink_type_0> <#slink_params_0> <slink_params_0>]{1..N}<br>+<br>+<replog_type>    = "ringbuffer" is currently the only available type<br>+<#replog_params> = # of args following this one intended for the replog (2 or 4)<br>
+<replog_params>  = <dev_path> <dev_start> [auto/create/open <size>]<br>+       <dev_path>  = device path of replication log (REPLOG) backing store<br>+       <dev_start> = offset to REPLOG header<br>
+       create      = The replication log will be initialized if not active<br>+                     and sized to "size".  (If already active, the create<br>+                     will fail.)  Size is always in sectors.<br>
+       open        = The replication log must be initialized and valid or<br>+                     the constructor will fail.<br>+       auto        = If a valid replication log header is found on the<br>+                     replication device, this will behave like 'open'.<br>
+                     Otherwise, this option behaves like 'create'.<br>+<br>+<slink_type>    = "blockdev" is currently the only available type<br>+<#slink_params> = 1/2/4<br>+<slink_params>  = <slink_nr> [<slink_policy> [<fall_behind> <N>]]<br>
+       <slink_nr>     = This is a unique number that is used to identify a<br>+                        particular site/location.  '0' is always used to<br>+                        identify the local site, while increasing integers<br>
+                        are used to identify remote sites.<br>+       <slink_policy> = The policy can be either 'sync' or 'async'.<br>+                        'sync' means write requests will not return until<br>
+                        the data is on the storage device.  'async' allows<br>+                        a device to "fall behind"; that is, outstanding<br>+                        write requests are waiting in the replication log<br>
+                        to be processed for this site, but it is not delaying<br>+                        the writes of other sites.<br>+       <fall_behind>  = This field is used to specify how far the user is<br>
+                        willing to allow write requests to this specific site<br>+                        to "fall behind" in processing before switching to<br>+                        a 'sync' policy.  This "fall behind" threshhold can<br>
+                        be specified in three ways: ios, size, or timeout.<br>+                        'ios' is the number of pending I/Os allowed (e.g.<br>+                        "ios 10000").  'size' is the amount of pending data<br>
+                        allowed (e.g. "size 200m").  Size labels include:<br>+                        s (sectors), k, m, g, t, p, and e.  'timeout' is<br>+                        the amount of time allowed for writes to be<br>
+                        outstanding.  Time labels include: s, m, h, and d.<br>+<br>+<br>+"replicator-dev" target parameters:<br>+-----------------------------------<br>+start> <length> replicator-dev<br>
+       <replicator_device> <dev_nr> \<br>+       [<slink_nr> <#dev_params> <dev_params><br>+        <dlog_type> <#dlog_params> <dlog_params>]{1..N}<br>+<br>+<replicator_device> = device previously constructed via "replication" target<br>
+<dev_nr>           = An integer that is used to 'tag' write requests as<br>+                     belonging to a particular set of devices - specifically,<br>+                     the devices that follow this argument (i.e. the site<br>
+                     link devices).<br>+<slink_nr>         = This number identifies the site/location where the next<br>+                     device to be specified comes from.  It is exactly the<br>+                     same number used to identify the site/location (and its<br>
+                     policies) in the "replicator" target.  Interestingly,<br>+                     while one might normally expect a "dev_type" argument<br>+                     here, it can be deduced from the site link number and<br>
+                     the 'slink_type' given in the "replication" target.<br>+<#dev_params>      = '1'  (The number of allowed parameters actually depends<br>+                     on the 'slink_type' given in the "replication" target.<br>
+                     Since our only option there is "blockdev", the only<br>+                     allowable number here is currently '1'.)<br>+<dev_params>       = 'dev_path'  (Again, since "blockdev" is the only<br>
+                     'slink_type' available, the only allowable argument here<br>+                     is the path to the device.)<br>+<dlog_type>        = Not to be confused with the "replicator log", this is<br>
+                     the type of dirty log associated with this particular<br>+                     device.  Dirty logs are used for synchronization, during<br>+                     initialization or fall behind conditions, to bring devices<br>
+                     into a coherent state with its peers - analogous to<br>+                     rebuilding a RAID1 (mirror) device.  Available dirty<br>+                     log types include: 'nolog', 'core', and 'disk'<br>
+<#dlog_params>     = The number of arguments required for a particular log<br>+                     type - 'nolog' = 0, 'core' = 1/2, 'disk' = 2/3.<br>+<dlog_params>      = 'nolog' => ~no arguments~<br>
+                     'core'  => <region_size> [sync | nosync]<br>+                     'disk'  => <dlog_dev_path> <region_size> [sync | nosync]<br>+       <region_size>   = This sets the granularity at which the dirty log<br>
+                         tracks what areas of the device is in-sync.<br>+       [sync | nosync] = Optionally specify whether the sync should be forced<br>+                         or avoided initially.<br>diff --git 2.6.33-rc1.orig/drivers/md/Kconfig 2.6.33-rc1/drivers/md/Kconfig<br>
index acb3a4e..62c9766 100644<br>--- 2.6.33-rc1.orig/drivers/md/Kconfig<br>+++ 2.6.33-rc1/drivers/md/Kconfig<br>@@ -313,6 +313,14 @@ config DM_DELAY<br><br>       If unsure, say N.<br><br>+config DM_REPLICATOR<br>+       tristate "Replication target (EXPERIMENTAL)"<br>
+       depends on BLK_DEV_DM && EXPERIMENTAL<br>+       ---help---<br>+       A target that supports replication of local devices to remote sites.<br>+<br>+       If unsure, say N.<br>+<br> config DM_UEVENT<br>       bool "DM uevents (EXPERIMENTAL)"<br>
       depends on BLK_DEV_DM && EXPERIMENTAL<br>diff --git 2.6.33-rc1.orig/drivers/md/Makefile 2.6.33-rc1/drivers/md/Makefile<br>index e355e7f..be05b39 100644<br>--- 2.6.33-rc1.orig/drivers/md/Makefile<br>+++ 2.6.33-rc1/drivers/md/Makefile<br>
@@ -44,6 +44,7 @@ obj-$(CONFIG_DM_SNAPSHOT)     += dm-snapshot.o<br> obj-$(CONFIG_DM_MIRROR)                += dm-mirror.o dm-log.o dm-region-hash.o<br> obj-$(CONFIG_DM_LOG_USERSPACE) += dm-log-userspace.o<br> obj-$(CONFIG_DM_ZERO)          += dm-zero.o<br>
+obj-$(CONFIG_DM_REPLICATOR)    += dm-log.o dm-registry.o<br><br> quiet_cmd_unroll = UNROLL  $@<br>      cmd_unroll = $(AWK) -f$(srctree)/$(src)/unroll.awk -vN=$(UNROLL) \<br>diff --git 2.6.33-rc1.orig/drivers/md/dm-registry.c 2.6.33-rc1/drivers/md/dm-registry.c<br>
new file mode 100644<br>index 0000000..fb8abbf<br>--- /dev/null<br>+++ 2.6.33-rc1/drivers/md/dm-registry.c<br>@@ -0,0 +1,224 @@<br>+/*<br>+ * Copyright (C) 2009 Red Hat, Inc. All rights reserved.<br>+ *<br>+ * Module Author: Heinz Mauelshagen (<a href="mailto:heinzm@redhat.com">heinzm@redhat.com</a>)<br>
+ *<br>+ * Generic registry for arbitrary structures<br>+ * (needs dm_registry_type structure upfront each registered structure).<br>+ *<br>+ * This file is released under the GPL.<br>+ *<br>+ * FIXME: use as registry for e.g. dirty log types as well.<br>
+ */<br>+<br>+#include <linux/init.h><br>+#include <linux/module.h><br>+#include <linux/moduleparam.h><br>+<br>+#include "dm-registry.h"<br>+<br>+#define        DM_MSG_PREFIX   "dm-registry"<br>
+<br>+static const char *version = "0.001";<br>+<br>+/* Sizable class registry. */<br>+static unsigned num_classes;<br>+static struct list_head *_classes;<br>+static rwlock_t *_locks;<br>+<br>+void *<br>+dm_get_type(const char *type_name, enum dm_registry_class class)<br>
+{<br>+       struct dm_registry_type *t;<br>+<br>+       read_lock(_locks + class);<br>+       list_for_each_entry(t, _classes + class, list) {<br>+               if (!strcmp(type_name, t->name)) {<br>+                       if (!t->use_count && !try_module_get(t->module)) {<br>
+                               read_unlock(_locks + class);<br>+                               return ERR_PTR(-ENOMEM);<br>+                       }<br>+<br>+                       t->use_count++;<br>+                       read_unlock(_locks + class);<br>
+                       return t;<br>+               }<br>+       }<br>+<br>+       read_unlock(_locks + class);<br>+       return ERR_PTR(-ENOENT);<br>+}<br>+EXPORT_SYMBOL(dm_get_type);<br>+<br>+void<br>+dm_put_type(void *type, enum dm_registry_class class)<br>
+{<br>+       struct dm_registry_type *t = type;<br>+<br>+       read_lock(_locks + class);<br>+       if (!--t->use_count)<br>+               module_put(t->module);<br>+<br>+       read_unlock(_locks + class);<br>+}<br>
+EXPORT_SYMBOL(dm_put_type);<br>+<br>+/* Add a type to the registry. */<br>+int<br>+dm_register_type(void *type, enum dm_registry_class class)<br>+{<br>+       struct dm_registry_type *t = type, *tt;<br>+<br>+       if (unlikely(class >= num_classes))<br>
+               return -EINVAL;<br>+<br>+       tt = dm_get_type(t->name, class);<br>+       if (unlikely(!IS_ERR(tt))) {<br>+               dm_put_type(t, class);<br>+               return -EEXIST;<br>+       }<br>+<br>
+       write_lock(_locks + class);<br>+       t->use_count = 0;<br>+       list_add(&t->list, _classes + class);<br>+       write_unlock(_locks + class);<br>+<br>+       return 0;<br>+}<br>+EXPORT_SYMBOL(dm_register_type);<br>
+<br>+/* Remove a type from the registry. */<br>+int<br>+dm_unregister_type(void *type, enum dm_registry_class class)<br>+{<br>+       struct dm_registry_type *t = type;<br>+<br>+       if (unlikely(class >= num_classes)) {<br>
+               DMERR("Attempt to unregister invalid class");<br>+               return -EINVAL;<br>+       }<br>+<br>+       write_lock(_locks + class);<br>+<br>+       if (unlikely(t->use_count)) {<br>+               write_unlock(_locks + class);<br>
+               DMWARN("Attempt to unregister a type that is still in use");<br>+               return -ETXTBSY;<br>+       } else<br>+               list_del(&t->list);<br>+<br>+       write_unlock(_locks + class);<br>
+       return 0;<br>+}<br>+EXPORT_SYMBOL(dm_unregister_type);<br>+<br>+/*<br>+ * Return kmalloc'ed NULL terminated pointer<br>+ * array of all type names of the given class.<br>+ *<br>+ * Caller has to kfree the array!.<br>
+ */<br>+const char **dm_types_list(enum dm_registry_class class)<br>+{<br>+       unsigned i = 0, count = 0;<br>+       const char **r;<br>+       struct dm_registry_type *t;<br>+<br>+       /* First count the registered types in the class. */<br>
+       read_lock(_locks + class);<br>+       list_for_each_entry(t, _classes + class, list)<br>+               count++;<br>+       read_unlock(_locks + class);<br>+<br>+       /* None registered in this class. */<br>+       if (!count)<br>
+               return NULL;<br>+<br>+       /* One member more for array NULL termination. */<br>+       r = kzalloc((count + 1) * sizeof(*r), GFP_KERNEL);<br>+       if (!r)<br>+               return ERR_PTR(-ENOMEM);<br>
+<br>+       /*<br>+        * Go with the counted ones.<br>+        * Any new added ones after we counted will be ignored!<br>+        */<br>+       read_lock(_locks + class);<br>+       list_for_each_entry(t, _classes + class, list) {<br>
+               r[i++] = t->name;<br>+               if (!--count)<br>+                       break;<br>+       }<br>+       read_unlock(_locks + class);<br>+<br>+       return r;<br>+}<br>+EXPORT_SYMBOL(dm_types_list);<br>
+<br>+int __init<br>+dm_registry_init(void)<br>+{<br>+       unsigned n;<br>+<br>+       BUG_ON(_classes);<br>+       BUG_ON(_locks);<br>+<br>+       /* Module parameter given ? */<br>+       if (!num_classes)<br>+               num_classes = DM_REGISTRY_CLASS_END;<br>
+<br>+       n = num_classes;<br>+       _classes = kmalloc(n * sizeof(*_classes), GFP_KERNEL);<br>+       if (!_classes) {<br>+               DMERR("Failed to allocate classes registry");<br>+               return -ENOMEM;<br>
+       }<br>+<br>+       _locks = kmalloc(n * sizeof(*_locks), GFP_KERNEL);<br>+       if (!_locks) {<br>+               DMERR("Failed to allocate classes locks");<br>+               kfree(_classes);<br>+               _classes = NULL;<br>
+               return -ENOMEM;<br>+       }<br>+<br>+       while (n--) {<br>+               INIT_LIST_HEAD(_classes + n);<br>+               rwlock_init(_locks + n);<br>+       }<br>+<br>+       DMINFO("initialized %s for max %u classes", version, num_classes);<br>
+       return 0;<br>+}<br>+<br>+void __exit<br>+dm_registry_exit(void)<br>+{<br>+       BUG_ON(!_classes);<br>+       BUG_ON(!_locks);<br>+<br>+       kfree(_classes);<br>+       _classes = NULL;<br>+       kfree(_locks);<br>
+       _locks = NULL;<br>+       DMINFO("exit %s", version);<br>+}<br>+<br>+/* Module hooks */<br>+module_init(dm_registry_init);<br>+module_exit(dm_registry_exit);<br>+module_param(num_classes, uint, 0);<br>+MODULE_PARM_DESC(num_classes, "Maximum number of classes");<br>
+MODULE_DESCRIPTION(DM_NAME "device-mapper registry");<br>+MODULE_AUTHOR("Heinz Mauelshagen <<a href="mailto:heinzm@redhat.com">heinzm@redhat.com</a>>");<br>+MODULE_LICENSE("GPL");<br>+<br>
+#ifndef MODULE<br>+static int __init num_classes_setup(char *str)<br>+{<br>+       num_classes = simple_strtol(str, NULL, 0);<br>+       return num_classes ? 1 : 0;<br>+}<br>+<br>+__setup("num_classes=", num_classes_setup);<br>
+#endif<br>diff --git 2.6.33-rc1.orig/drivers/md/dm-registry.h 2.6.33-rc1/drivers/md/dm-registry.h<br>new file mode 100644<br>index 0000000..1cb0ce8<br>--- /dev/null<br>+++ 2.6.33-rc1/drivers/md/dm-registry.h<br>@@ -0,0 +1,38 @@<br>
+/*<br>+ * Copyright (C) 2009 Red Hat, Inc. All rights reserved.<br>+ *<br>+ * Module Author: Heinz Mauelshagen (<a href="mailto:heinzm@redhat.com">heinzm@redhat.com</a>)<br>+ *<br>+ * Generic registry for arbitrary structures.<br>
+ * (needs dm_registry_type structure upfront each registered structure).<br>+ *<br>+ * This file is released under the GPL.<br>+ */<br>+<br>+#include "dm.h"<br>+<br>+#ifndef DM_REGISTRY_H<br>+#define DM_REGISTRY_H<br>
+<br>+enum dm_registry_class {<br>+       DM_REPLOG = 0,<br>+       DM_SLINK,<br>+       DM_LOG,<br>+       DM_REGION_HASH,<br>+       DM_REGISTRY_CLASS_END,<br>+};<br>+<br>+struct dm_registry_type {<br>+       struct list_head list;  /* Linked list of types in this class. */<br>
+       const char *name;<br>+       struct module *module;<br>+       unsigned int use_count;<br>+};<br>+<br>+void *dm_get_type(const char *type_name, enum dm_registry_class class);<br>+void dm_put_type(void *type, enum dm_registry_class class);<br>
+int dm_register_type(void *type, enum dm_registry_class class);<br>+int dm_unregister_type(void *type, enum dm_registry_class class);<br>+const char **dm_types_list(enum dm_registry_class class);<br>+<br>+#endif<br>--<br>
1.6.2.5<br><font color="#888888"><br>--<br>dm-devel mailing list<br><a href="mailto:dm-devel@redhat.com">dm-devel@redhat.com</a><br><a href="https://www.redhat.com/mailman/listinfo/dm-devel" target="_blank">https://www.redhat.com/mailman/listinfo/dm-devel</a><br>
</font></blockquote></div><br>