xref: /openbmc/linux/drivers/md/dm-target.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  * Copyright (C) 2001 Sistina Software (UK) Limited
3*1da177e4SLinus Torvalds  *
4*1da177e4SLinus Torvalds  * This file is released under the GPL.
5*1da177e4SLinus Torvalds  */
6*1da177e4SLinus Torvalds 
7*1da177e4SLinus Torvalds #include "dm.h"
8*1da177e4SLinus Torvalds 
9*1da177e4SLinus Torvalds #include <linux/module.h>
10*1da177e4SLinus Torvalds #include <linux/init.h>
11*1da177e4SLinus Torvalds #include <linux/kmod.h>
12*1da177e4SLinus Torvalds #include <linux/bio.h>
13*1da177e4SLinus Torvalds #include <linux/slab.h>
14*1da177e4SLinus Torvalds 
15*1da177e4SLinus Torvalds struct tt_internal {
16*1da177e4SLinus Torvalds 	struct target_type tt;
17*1da177e4SLinus Torvalds 
18*1da177e4SLinus Torvalds 	struct list_head list;
19*1da177e4SLinus Torvalds 	long use;
20*1da177e4SLinus Torvalds };
21*1da177e4SLinus Torvalds 
22*1da177e4SLinus Torvalds static LIST_HEAD(_targets);
23*1da177e4SLinus Torvalds static DECLARE_RWSEM(_lock);
24*1da177e4SLinus Torvalds 
25*1da177e4SLinus Torvalds #define DM_MOD_NAME_SIZE 32
26*1da177e4SLinus Torvalds 
27*1da177e4SLinus Torvalds static inline struct tt_internal *__find_target_type(const char *name)
28*1da177e4SLinus Torvalds {
29*1da177e4SLinus Torvalds 	struct tt_internal *ti;
30*1da177e4SLinus Torvalds 
31*1da177e4SLinus Torvalds 	list_for_each_entry (ti, &_targets, list)
32*1da177e4SLinus Torvalds 		if (!strcmp(name, ti->tt.name))
33*1da177e4SLinus Torvalds 			return ti;
34*1da177e4SLinus Torvalds 
35*1da177e4SLinus Torvalds 	return NULL;
36*1da177e4SLinus Torvalds }
37*1da177e4SLinus Torvalds 
38*1da177e4SLinus Torvalds static struct tt_internal *get_target_type(const char *name)
39*1da177e4SLinus Torvalds {
40*1da177e4SLinus Torvalds 	struct tt_internal *ti;
41*1da177e4SLinus Torvalds 
42*1da177e4SLinus Torvalds 	down_read(&_lock);
43*1da177e4SLinus Torvalds 
44*1da177e4SLinus Torvalds 	ti = __find_target_type(name);
45*1da177e4SLinus Torvalds 	if (ti) {
46*1da177e4SLinus Torvalds 		if ((ti->use == 0) && !try_module_get(ti->tt.module))
47*1da177e4SLinus Torvalds 			ti = NULL;
48*1da177e4SLinus Torvalds 		else
49*1da177e4SLinus Torvalds 			ti->use++;
50*1da177e4SLinus Torvalds 	}
51*1da177e4SLinus Torvalds 
52*1da177e4SLinus Torvalds 	up_read(&_lock);
53*1da177e4SLinus Torvalds 	return ti;
54*1da177e4SLinus Torvalds }
55*1da177e4SLinus Torvalds 
56*1da177e4SLinus Torvalds static void load_module(const char *name)
57*1da177e4SLinus Torvalds {
58*1da177e4SLinus Torvalds 	request_module("dm-%s", name);
59*1da177e4SLinus Torvalds }
60*1da177e4SLinus Torvalds 
61*1da177e4SLinus Torvalds struct target_type *dm_get_target_type(const char *name)
62*1da177e4SLinus Torvalds {
63*1da177e4SLinus Torvalds 	struct tt_internal *ti = get_target_type(name);
64*1da177e4SLinus Torvalds 
65*1da177e4SLinus Torvalds 	if (!ti) {
66*1da177e4SLinus Torvalds 		load_module(name);
67*1da177e4SLinus Torvalds 		ti = get_target_type(name);
68*1da177e4SLinus Torvalds 	}
69*1da177e4SLinus Torvalds 
70*1da177e4SLinus Torvalds 	return ti ? &ti->tt : NULL;
71*1da177e4SLinus Torvalds }
72*1da177e4SLinus Torvalds 
73*1da177e4SLinus Torvalds void dm_put_target_type(struct target_type *t)
74*1da177e4SLinus Torvalds {
75*1da177e4SLinus Torvalds 	struct tt_internal *ti = (struct tt_internal *) t;
76*1da177e4SLinus Torvalds 
77*1da177e4SLinus Torvalds 	down_read(&_lock);
78*1da177e4SLinus Torvalds 	if (--ti->use == 0)
79*1da177e4SLinus Torvalds 		module_put(ti->tt.module);
80*1da177e4SLinus Torvalds 
81*1da177e4SLinus Torvalds 	if (ti->use < 0)
82*1da177e4SLinus Torvalds 		BUG();
83*1da177e4SLinus Torvalds 	up_read(&_lock);
84*1da177e4SLinus Torvalds 
85*1da177e4SLinus Torvalds 	return;
86*1da177e4SLinus Torvalds }
87*1da177e4SLinus Torvalds 
88*1da177e4SLinus Torvalds static struct tt_internal *alloc_target(struct target_type *t)
89*1da177e4SLinus Torvalds {
90*1da177e4SLinus Torvalds 	struct tt_internal *ti = kmalloc(sizeof(*ti), GFP_KERNEL);
91*1da177e4SLinus Torvalds 
92*1da177e4SLinus Torvalds 	if (ti) {
93*1da177e4SLinus Torvalds 		memset(ti, 0, sizeof(*ti));
94*1da177e4SLinus Torvalds 		ti->tt = *t;
95*1da177e4SLinus Torvalds 	}
96*1da177e4SLinus Torvalds 
97*1da177e4SLinus Torvalds 	return ti;
98*1da177e4SLinus Torvalds }
99*1da177e4SLinus Torvalds 
100*1da177e4SLinus Torvalds 
101*1da177e4SLinus Torvalds int dm_target_iterate(void (*iter_func)(struct target_type *tt,
102*1da177e4SLinus Torvalds 					void *param), void *param)
103*1da177e4SLinus Torvalds {
104*1da177e4SLinus Torvalds 	struct tt_internal *ti;
105*1da177e4SLinus Torvalds 
106*1da177e4SLinus Torvalds 	down_read(&_lock);
107*1da177e4SLinus Torvalds 	list_for_each_entry (ti, &_targets, list)
108*1da177e4SLinus Torvalds 		iter_func(&ti->tt, param);
109*1da177e4SLinus Torvalds 	up_read(&_lock);
110*1da177e4SLinus Torvalds 
111*1da177e4SLinus Torvalds 	return 0;
112*1da177e4SLinus Torvalds }
113*1da177e4SLinus Torvalds 
114*1da177e4SLinus Torvalds int dm_register_target(struct target_type *t)
115*1da177e4SLinus Torvalds {
116*1da177e4SLinus Torvalds 	int rv = 0;
117*1da177e4SLinus Torvalds 	struct tt_internal *ti = alloc_target(t);
118*1da177e4SLinus Torvalds 
119*1da177e4SLinus Torvalds 	if (!ti)
120*1da177e4SLinus Torvalds 		return -ENOMEM;
121*1da177e4SLinus Torvalds 
122*1da177e4SLinus Torvalds 	down_write(&_lock);
123*1da177e4SLinus Torvalds 	if (__find_target_type(t->name))
124*1da177e4SLinus Torvalds 		rv = -EEXIST;
125*1da177e4SLinus Torvalds 	else
126*1da177e4SLinus Torvalds 		list_add(&ti->list, &_targets);
127*1da177e4SLinus Torvalds 
128*1da177e4SLinus Torvalds 	up_write(&_lock);
129*1da177e4SLinus Torvalds 	if (rv)
130*1da177e4SLinus Torvalds 		kfree(ti);
131*1da177e4SLinus Torvalds 	return rv;
132*1da177e4SLinus Torvalds }
133*1da177e4SLinus Torvalds 
134*1da177e4SLinus Torvalds int dm_unregister_target(struct target_type *t)
135*1da177e4SLinus Torvalds {
136*1da177e4SLinus Torvalds 	struct tt_internal *ti;
137*1da177e4SLinus Torvalds 
138*1da177e4SLinus Torvalds 	down_write(&_lock);
139*1da177e4SLinus Torvalds 	if (!(ti = __find_target_type(t->name))) {
140*1da177e4SLinus Torvalds 		up_write(&_lock);
141*1da177e4SLinus Torvalds 		return -EINVAL;
142*1da177e4SLinus Torvalds 	}
143*1da177e4SLinus Torvalds 
144*1da177e4SLinus Torvalds 	if (ti->use) {
145*1da177e4SLinus Torvalds 		up_write(&_lock);
146*1da177e4SLinus Torvalds 		return -ETXTBSY;
147*1da177e4SLinus Torvalds 	}
148*1da177e4SLinus Torvalds 
149*1da177e4SLinus Torvalds 	list_del(&ti->list);
150*1da177e4SLinus Torvalds 	kfree(ti);
151*1da177e4SLinus Torvalds 
152*1da177e4SLinus Torvalds 	up_write(&_lock);
153*1da177e4SLinus Torvalds 	return 0;
154*1da177e4SLinus Torvalds }
155*1da177e4SLinus Torvalds 
156*1da177e4SLinus Torvalds /*
157*1da177e4SLinus Torvalds  * io-err: always fails an io, useful for bringing
158*1da177e4SLinus Torvalds  * up LVs that have holes in them.
159*1da177e4SLinus Torvalds  */
160*1da177e4SLinus Torvalds static int io_err_ctr(struct dm_target *ti, unsigned int argc, char **args)
161*1da177e4SLinus Torvalds {
162*1da177e4SLinus Torvalds 	return 0;
163*1da177e4SLinus Torvalds }
164*1da177e4SLinus Torvalds 
165*1da177e4SLinus Torvalds static void io_err_dtr(struct dm_target *ti)
166*1da177e4SLinus Torvalds {
167*1da177e4SLinus Torvalds 	/* empty */
168*1da177e4SLinus Torvalds }
169*1da177e4SLinus Torvalds 
170*1da177e4SLinus Torvalds static int io_err_map(struct dm_target *ti, struct bio *bio,
171*1da177e4SLinus Torvalds 		      union map_info *map_context)
172*1da177e4SLinus Torvalds {
173*1da177e4SLinus Torvalds 	return -EIO;
174*1da177e4SLinus Torvalds }
175*1da177e4SLinus Torvalds 
176*1da177e4SLinus Torvalds static struct target_type error_target = {
177*1da177e4SLinus Torvalds 	.name = "error",
178*1da177e4SLinus Torvalds 	.version = {1, 0, 1},
179*1da177e4SLinus Torvalds 	.ctr  = io_err_ctr,
180*1da177e4SLinus Torvalds 	.dtr  = io_err_dtr,
181*1da177e4SLinus Torvalds 	.map  = io_err_map,
182*1da177e4SLinus Torvalds };
183*1da177e4SLinus Torvalds 
184*1da177e4SLinus Torvalds int __init dm_target_init(void)
185*1da177e4SLinus Torvalds {
186*1da177e4SLinus Torvalds 	return dm_register_target(&error_target);
187*1da177e4SLinus Torvalds }
188*1da177e4SLinus Torvalds 
189*1da177e4SLinus Torvalds void dm_target_exit(void)
190*1da177e4SLinus Torvalds {
191*1da177e4SLinus Torvalds 	if (dm_unregister_target(&error_target))
192*1da177e4SLinus Torvalds 		DMWARN("error target unregistration failed");
193*1da177e4SLinus Torvalds }
194*1da177e4SLinus Torvalds 
195*1da177e4SLinus Torvalds EXPORT_SYMBOL(dm_register_target);
196*1da177e4SLinus Torvalds EXPORT_SYMBOL(dm_unregister_target);
197