Merge branch 'modsplit-Oct31_2011' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / md / dm-log-userspace-base.c
index 1021c89..9429159 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/dm-dirty-log.h>
 #include <linux/device-mapper.h>
 #include <linux/dm-log-userspace.h>
+#include <linux/module.h>
 
 #include "dm-log-userspace-transfer.h"
 
@@ -30,6 +31,7 @@ struct flush_entry {
 
 struct log_c {
        struct dm_target *ti;
+       struct dm_dev *log_dev;
        uint32_t region_size;
        region_t region_count;
        uint64_t luid;
@@ -146,7 +148,7 @@ static int build_constructor_string(struct dm_target *ti,
  *     <UUID> <other args>
  * Where 'other args' is the userspace implementation specific log
  * arguments.  An example might be:
- *     <UUID> clustered_disk <arg count> <log dev> <region_size> [[no]sync]
+ *     <UUID> clustered-disk <arg count> <log dev> <region_size> [[no]sync]
  *
  * So, this module will strip off the <UUID> for identification purposes
  * when communicating with userspace about a log; but will pass on everything
@@ -161,13 +163,15 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti,
        struct log_c *lc = NULL;
        uint64_t rdata;
        size_t rdata_size = sizeof(rdata);
+       char *devices_rdata = NULL;
+       size_t devices_rdata_size = DM_NAME_LEN;
 
        if (argc < 3) {
                DMWARN("Too few arguments to userspace dirty log");
                return -EINVAL;
        }
 
-       lc = kmalloc(sizeof(*lc), GFP_KERNEL);
+       lc = kzalloc(sizeof(*lc), GFP_KERNEL);
        if (!lc) {
                DMWARN("Unable to allocate userspace log context.");
                return -ENOMEM;
@@ -195,9 +199,19 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti,
                return str_size;
        }
 
-       /* Send table string */
+       devices_rdata = kzalloc(devices_rdata_size, GFP_KERNEL);
+       if (!devices_rdata) {
+               DMERR("Failed to allocate memory for device information");
+               r = -ENOMEM;
+               goto out;
+       }
+
+       /*
+        * Send table string and get back any opened device.
+        */
        r = dm_consult_userspace(lc->uuid, lc->luid, DM_ULOG_CTR,
-                                ctr_str, str_size, NULL, NULL);
+                                ctr_str, str_size,
+                                devices_rdata, &devices_rdata_size);
 
        if (r < 0) {
                if (r == -ESRCH)
@@ -220,7 +234,20 @@ static int userspace_ctr(struct dm_dirty_log *log, struct dm_target *ti,
        lc->region_size = (uint32_t)rdata;
        lc->region_count = dm_sector_div_up(ti->len, lc->region_size);
 
+       if (devices_rdata_size) {
+               if (devices_rdata[devices_rdata_size - 1] != '\0') {
+                       DMERR("DM_ULOG_CTR device return string not properly terminated");
+                       r = -EINVAL;
+                       goto out;
+               }
+               r = dm_get_device(ti, devices_rdata,
+                                 dm_table_get_mode(ti->table), &lc->log_dev);
+               if (r)
+                       DMERR("Failed to register %s with device-mapper",
+                             devices_rdata);
+       }
 out:
+       kfree(devices_rdata);
        if (r) {
                kfree(lc);
                kfree(ctr_str);
@@ -241,6 +268,9 @@ static void userspace_dtr(struct dm_dirty_log *log)
                                 NULL, 0,
                                 NULL, NULL);
 
+       if (lc->log_dev)
+               dm_put_device(lc->ti, lc->log_dev);
+
        kfree(lc->usr_argv_str);
        kfree(lc);