xref: /openbmc/linux/drivers/md/dm-target.c (revision 5de719e3d01b4abe0de0d7b857148a880ff2a90b)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Copyright (C) 2001 Sistina Software (UK) Limited
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * This file is released under the GPL.
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds 
74cc96131SMike Snitzer #include "dm-core.h"
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds #include <linux/module.h>
101da177e4SLinus Torvalds #include <linux/init.h>
111da177e4SLinus Torvalds #include <linux/kmod.h>
121da177e4SLinus Torvalds #include <linux/bio.h>
131da177e4SLinus Torvalds 
1472d94861SAlasdair G Kergon #define DM_MSG_PREFIX "target"
1572d94861SAlasdair G Kergon 
161da177e4SLinus Torvalds static LIST_HEAD(_targets);
171da177e4SLinus Torvalds static DECLARE_RWSEM(_lock);
181da177e4SLinus Torvalds 
1945194e4fSCheng Renquan static inline struct target_type *__find_target_type(const char *name)
201da177e4SLinus Torvalds {
2145194e4fSCheng Renquan 	struct target_type *tt;
221da177e4SLinus Torvalds 
2345194e4fSCheng Renquan 	list_for_each_entry(tt, &_targets, list)
2445194e4fSCheng Renquan 		if (!strcmp(name, tt->name))
2545194e4fSCheng Renquan 			return tt;
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds 	return NULL;
281da177e4SLinus Torvalds }
291da177e4SLinus Torvalds 
3045194e4fSCheng Renquan static struct target_type *get_target_type(const char *name)
311da177e4SLinus Torvalds {
3245194e4fSCheng Renquan 	struct target_type *tt;
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds 	down_read(&_lock);
351da177e4SLinus Torvalds 
3645194e4fSCheng Renquan 	tt = __find_target_type(name);
3745194e4fSCheng Renquan 	if (tt && !try_module_get(tt->module))
3845194e4fSCheng Renquan 		tt = NULL;
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds 	up_read(&_lock);
4145194e4fSCheng Renquan 	return tt;
421da177e4SLinus Torvalds }
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds static void load_module(const char *name)
451da177e4SLinus Torvalds {
461da177e4SLinus Torvalds 	request_module("dm-%s", name);
471da177e4SLinus Torvalds }
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds struct target_type *dm_get_target_type(const char *name)
501da177e4SLinus Torvalds {
5145194e4fSCheng Renquan 	struct target_type *tt = get_target_type(name);
521da177e4SLinus Torvalds 
5345194e4fSCheng Renquan 	if (!tt) {
541da177e4SLinus Torvalds 		load_module(name);
5545194e4fSCheng Renquan 		tt = get_target_type(name);
561da177e4SLinus Torvalds 	}
571da177e4SLinus Torvalds 
5845194e4fSCheng Renquan 	return tt;
591da177e4SLinus Torvalds }
601da177e4SLinus Torvalds 
6145194e4fSCheng Renquan void dm_put_target_type(struct target_type *tt)
621da177e4SLinus Torvalds {
631da177e4SLinus Torvalds 	down_read(&_lock);
6445194e4fSCheng Renquan 	module_put(tt->module);
651da177e4SLinus Torvalds 	up_read(&_lock);
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds int dm_target_iterate(void (*iter_func)(struct target_type *tt,
691da177e4SLinus Torvalds 					void *param), void *param)
701da177e4SLinus Torvalds {
7145194e4fSCheng Renquan 	struct target_type *tt;
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds 	down_read(&_lock);
7445194e4fSCheng Renquan 	list_for_each_entry(tt, &_targets, list)
7545194e4fSCheng Renquan 		iter_func(tt, param);
761da177e4SLinus Torvalds 	up_read(&_lock);
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds 	return 0;
791da177e4SLinus Torvalds }
801da177e4SLinus Torvalds 
8145194e4fSCheng Renquan int dm_register_target(struct target_type *tt)
821da177e4SLinus Torvalds {
831da177e4SLinus Torvalds 	int rv = 0;
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds 	down_write(&_lock);
8645194e4fSCheng Renquan 	if (__find_target_type(tt->name))
871da177e4SLinus Torvalds 		rv = -EEXIST;
881da177e4SLinus Torvalds 	else
8945194e4fSCheng Renquan 		list_add(&tt->list, &_targets);
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds 	up_write(&_lock);
921da177e4SLinus Torvalds 	return rv;
931da177e4SLinus Torvalds }
941da177e4SLinus Torvalds 
9545194e4fSCheng Renquan void dm_unregister_target(struct target_type *tt)
961da177e4SLinus Torvalds {
971da177e4SLinus Torvalds 	down_write(&_lock);
9845194e4fSCheng Renquan 	if (!__find_target_type(tt->name)) {
9945194e4fSCheng Renquan 		DMCRIT("Unregistering unrecognised target: %s", tt->name);
10010d3bd09SMikulas Patocka 		BUG();
1011da177e4SLinus Torvalds 	}
1021da177e4SLinus Torvalds 
10345194e4fSCheng Renquan 	list_del(&tt->list);
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 	up_write(&_lock);
1061da177e4SLinus Torvalds }
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds /*
1091da177e4SLinus Torvalds  * io-err: always fails an io, useful for bringing
1101da177e4SLinus Torvalds  * up LVs that have holes in them.
1111da177e4SLinus Torvalds  */
11245194e4fSCheng Renquan static int io_err_ctr(struct dm_target *tt, unsigned int argc, char **args)
1131da177e4SLinus Torvalds {
11438e1b257SMike Snitzer 	/*
11538e1b257SMike Snitzer 	 * Return error for discards instead of -EOPNOTSUPP
11638e1b257SMike Snitzer 	 */
11755a62eefSAlasdair G Kergon 	tt->num_discard_bios = 1;
11838e1b257SMike Snitzer 
1191da177e4SLinus Torvalds 	return 0;
1201da177e4SLinus Torvalds }
1211da177e4SLinus Torvalds 
12245194e4fSCheng Renquan static void io_err_dtr(struct dm_target *tt)
1231da177e4SLinus Torvalds {
1241da177e4SLinus Torvalds 	/* empty */
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds 
1277de3ee57SMikulas Patocka static int io_err_map(struct dm_target *tt, struct bio *bio)
1281da177e4SLinus Torvalds {
129846785e6SChristoph Hellwig 	return DM_MAPIO_KILL;
1301da177e4SLinus Torvalds }
1311da177e4SLinus Torvalds 
132e5863d9aSMike Snitzer static int io_err_clone_and_map_rq(struct dm_target *ti, struct request *rq,
133e5863d9aSMike Snitzer 				   union map_info *map_context,
134e5863d9aSMike Snitzer 				   struct request **clone)
135e5863d9aSMike Snitzer {
136412445acSChristoph Hellwig 	return DM_MAPIO_KILL;
137e5863d9aSMike Snitzer }
138e5863d9aSMike Snitzer 
139*5de719e3SYufen Yu static void io_err_release_clone_rq(struct request *clone,
140*5de719e3SYufen Yu 				    union map_info *map_context)
141e5863d9aSMike Snitzer {
142e5863d9aSMike Snitzer }
143e5863d9aSMike Snitzer 
144817bf402SDan Williams static long io_err_dax_direct_access(struct dm_target *ti, pgoff_t pgoff,
145817bf402SDan Williams 		long nr_pages, void **kaddr, pfn_t *pfn)
146f8df1fdfSMike Snitzer {
147f8df1fdfSMike Snitzer 	return -EIO;
148f8df1fdfSMike Snitzer }
149f8df1fdfSMike Snitzer 
1501da177e4SLinus Torvalds static struct target_type error_target = {
1511da177e4SLinus Torvalds 	.name = "error",
152f8df1fdfSMike Snitzer 	.version = {1, 5, 0},
153f083b09bSMike Snitzer 	.features = DM_TARGET_WILDCARD,
1541da177e4SLinus Torvalds 	.ctr  = io_err_ctr,
1551da177e4SLinus Torvalds 	.dtr  = io_err_dtr,
1561da177e4SLinus Torvalds 	.map  = io_err_map,
157e5863d9aSMike Snitzer 	.clone_and_map_rq = io_err_clone_and_map_rq,
158e5863d9aSMike Snitzer 	.release_clone_rq = io_err_release_clone_rq,
159817bf402SDan Williams 	.direct_access = io_err_dax_direct_access,
1601da177e4SLinus Torvalds };
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds int __init dm_target_init(void)
1631da177e4SLinus Torvalds {
1641da177e4SLinus Torvalds 	return dm_register_target(&error_target);
1651da177e4SLinus Torvalds }
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds void dm_target_exit(void)
1681da177e4SLinus Torvalds {
16910d3bd09SMikulas Patocka 	dm_unregister_target(&error_target);
1701da177e4SLinus Torvalds }
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds EXPORT_SYMBOL(dm_register_target);
1731da177e4SLinus Torvalds EXPORT_SYMBOL(dm_unregister_target);
174