Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / md / dm-target.c
diff --git a/kernel/drivers/md/dm-target.c b/kernel/drivers/md/dm-target.c
new file mode 100644 (file)
index 0000000..925ec1b
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm.h"
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/bio.h>
+
+#define DM_MSG_PREFIX "target"
+
+static LIST_HEAD(_targets);
+static DECLARE_RWSEM(_lock);
+
+#define DM_MOD_NAME_SIZE 32
+
+static inline struct target_type *__find_target_type(const char *name)
+{
+       struct target_type *tt;
+
+       list_for_each_entry(tt, &_targets, list)
+               if (!strcmp(name, tt->name))
+                       return tt;
+
+       return NULL;
+}
+
+static struct target_type *get_target_type(const char *name)
+{
+       struct target_type *tt;
+
+       down_read(&_lock);
+
+       tt = __find_target_type(name);
+       if (tt && !try_module_get(tt->module))
+               tt = NULL;
+
+       up_read(&_lock);
+       return tt;
+}
+
+static void load_module(const char *name)
+{
+       request_module("dm-%s", name);
+}
+
+struct target_type *dm_get_target_type(const char *name)
+{
+       struct target_type *tt = get_target_type(name);
+
+       if (!tt) {
+               load_module(name);
+               tt = get_target_type(name);
+       }
+
+       return tt;
+}
+
+void dm_put_target_type(struct target_type *tt)
+{
+       down_read(&_lock);
+       module_put(tt->module);
+       up_read(&_lock);
+}
+
+int dm_target_iterate(void (*iter_func)(struct target_type *tt,
+                                       void *param), void *param)
+{
+       struct target_type *tt;
+
+       down_read(&_lock);
+       list_for_each_entry(tt, &_targets, list)
+               iter_func(tt, param);
+       up_read(&_lock);
+
+       return 0;
+}
+
+int dm_register_target(struct target_type *tt)
+{
+       int rv = 0;
+
+       down_write(&_lock);
+       if (__find_target_type(tt->name))
+               rv = -EEXIST;
+       else
+               list_add(&tt->list, &_targets);
+
+       up_write(&_lock);
+       return rv;
+}
+
+void dm_unregister_target(struct target_type *tt)
+{
+       down_write(&_lock);
+       if (!__find_target_type(tt->name)) {
+               DMCRIT("Unregistering unrecognised target: %s", tt->name);
+               BUG();
+       }
+
+       list_del(&tt->list);
+
+       up_write(&_lock);
+}
+
+/*
+ * io-err: always fails an io, useful for bringing
+ * up LVs that have holes in them.
+ */
+static int io_err_ctr(struct dm_target *tt, unsigned int argc, char **args)
+{
+       /*
+        * Return error for discards instead of -EOPNOTSUPP
+        */
+       tt->num_discard_bios = 1;
+
+       return 0;
+}
+
+static void io_err_dtr(struct dm_target *tt)
+{
+       /* empty */
+}
+
+static int io_err_map(struct dm_target *tt, struct bio *bio)
+{
+       return -EIO;
+}
+
+static int io_err_map_rq(struct dm_target *ti, struct request *clone,
+                        union map_info *map_context)
+{
+       return -EIO;
+}
+
+static int io_err_clone_and_map_rq(struct dm_target *ti, struct request *rq,
+                                  union map_info *map_context,
+                                  struct request **clone)
+{
+       return -EIO;
+}
+
+static void io_err_release_clone_rq(struct request *clone)
+{
+}
+
+static struct target_type error_target = {
+       .name = "error",
+       .version = {1, 3, 0},
+       .ctr  = io_err_ctr,
+       .dtr  = io_err_dtr,
+       .map  = io_err_map,
+       .map_rq = io_err_map_rq,
+       .clone_and_map_rq = io_err_clone_and_map_rq,
+       .release_clone_rq = io_err_release_clone_rq,
+};
+
+int __init dm_target_init(void)
+{
+       return dm_register_target(&error_target);
+}
+
+void dm_target_exit(void)
+{
+       dm_unregister_target(&error_target);
+}
+
+EXPORT_SYMBOL(dm_register_target);
+EXPORT_SYMBOL(dm_unregister_target);