blob: 04feccf2a997947968260029419e7813cb222553 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (C) 2001 Sistina Software (UK) Limited
3 *
4 * This file is released under the GPL.
5 */
6
7#include "dm.h"
8
9#include <linux/module.h>
10#include <linux/init.h>
11#include <linux/kmod.h>
12#include <linux/bio.h>
13#include <linux/slab.h>
14
Alasdair G Kergon72d94862006-06-26 00:27:35 -070015#define DM_MSG_PREFIX "target"
16
Linus Torvalds1da177e2005-04-16 15:20:36 -070017static LIST_HEAD(_targets);
18static DECLARE_RWSEM(_lock);
19
20#define DM_MOD_NAME_SIZE 32
21
Cheng Renquan45194e42009-04-02 19:55:28 +010022static inline struct target_type *__find_target_type(const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -070023{
Cheng Renquan45194e42009-04-02 19:55:28 +010024 struct target_type *tt;
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Cheng Renquan45194e42009-04-02 19:55:28 +010026 list_for_each_entry(tt, &_targets, list)
27 if (!strcmp(name, tt->name))
28 return tt;
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30 return NULL;
31}
32
Cheng Renquan45194e42009-04-02 19:55:28 +010033static struct target_type *get_target_type(const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -070034{
Cheng Renquan45194e42009-04-02 19:55:28 +010035 struct target_type *tt;
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37 down_read(&_lock);
38
Cheng Renquan45194e42009-04-02 19:55:28 +010039 tt = __find_target_type(name);
40 if (tt && !try_module_get(tt->module))
41 tt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43 up_read(&_lock);
Cheng Renquan45194e42009-04-02 19:55:28 +010044 return tt;
Linus Torvalds1da177e2005-04-16 15:20:36 -070045}
46
47static void load_module(const char *name)
48{
49 request_module("dm-%s", name);
50}
51
52struct target_type *dm_get_target_type(const char *name)
53{
Cheng Renquan45194e42009-04-02 19:55:28 +010054 struct target_type *tt = get_target_type(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Cheng Renquan45194e42009-04-02 19:55:28 +010056 if (!tt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 load_module(name);
Cheng Renquan45194e42009-04-02 19:55:28 +010058 tt = get_target_type(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 }
60
Cheng Renquan45194e42009-04-02 19:55:28 +010061 return tt;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062}
63
Cheng Renquan45194e42009-04-02 19:55:28 +010064void dm_put_target_type(struct target_type *tt)
Linus Torvalds1da177e2005-04-16 15:20:36 -070065{
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 down_read(&_lock);
Cheng Renquan45194e42009-04-02 19:55:28 +010067 module_put(tt->module);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 up_read(&_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070069}
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071int dm_target_iterate(void (*iter_func)(struct target_type *tt,
72 void *param), void *param)
73{
Cheng Renquan45194e42009-04-02 19:55:28 +010074 struct target_type *tt;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
76 down_read(&_lock);
Cheng Renquan45194e42009-04-02 19:55:28 +010077 list_for_each_entry(tt, &_targets, list)
78 iter_func(tt, param);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 up_read(&_lock);
80
81 return 0;
82}
83
Cheng Renquan45194e42009-04-02 19:55:28 +010084int dm_register_target(struct target_type *tt)
Linus Torvalds1da177e2005-04-16 15:20:36 -070085{
86 int rv = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
88 down_write(&_lock);
Cheng Renquan45194e42009-04-02 19:55:28 +010089 if (__find_target_type(tt->name))
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 rv = -EEXIST;
91 else
Cheng Renquan45194e42009-04-02 19:55:28 +010092 list_add(&tt->list, &_targets);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
94 up_write(&_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 return rv;
96}
97
Cheng Renquan45194e42009-04-02 19:55:28 +010098void dm_unregister_target(struct target_type *tt)
Linus Torvalds1da177e2005-04-16 15:20:36 -070099{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 down_write(&_lock);
Cheng Renquan45194e42009-04-02 19:55:28 +0100101 if (!__find_target_type(tt->name)) {
102 DMCRIT("Unregistering unrecognised target: %s", tt->name);
Mikulas Patocka10d3bd02009-01-06 03:04:58 +0000103 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 }
105
Cheng Renquan45194e42009-04-02 19:55:28 +0100106 list_del(&tt->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
108 up_write(&_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109}
110
111/*
112 * io-err: always fails an io, useful for bringing
113 * up LVs that have holes in them.
114 */
Cheng Renquan45194e42009-04-02 19:55:28 +0100115static int io_err_ctr(struct dm_target *tt, unsigned int argc, char **args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116{
117 return 0;
118}
119
Cheng Renquan45194e42009-04-02 19:55:28 +0100120static void io_err_dtr(struct dm_target *tt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121{
122 /* empty */
123}
124
Cheng Renquan45194e42009-04-02 19:55:28 +0100125static int io_err_map(struct dm_target *tt, struct bio *bio,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 union map_info *map_context)
127{
128 return -EIO;
129}
130
131static struct target_type error_target = {
132 .name = "error",
133 .version = {1, 0, 1},
134 .ctr = io_err_ctr,
135 .dtr = io_err_dtr,
136 .map = io_err_map,
137};
138
139int __init dm_target_init(void)
140{
141 return dm_register_target(&error_target);
142}
143
144void dm_target_exit(void)
145{
Mikulas Patocka10d3bd02009-01-06 03:04:58 +0000146 dm_unregister_target(&error_target);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147}
148
149EXPORT_SYMBOL(dm_register_target);
150EXPORT_SYMBOL(dm_unregister_target);