xref: /openbmc/linux/drivers/md/dm-target.c (revision e511c4a3d2a1f64aafc1f5df37a2ffcf7ef91b55)
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>
13*e511c4a3SJane Chu #include <linux/dax.h>
141da177e4SLinus Torvalds 
1572d94861SAlasdair G Kergon #define DM_MSG_PREFIX "target"
1672d94861SAlasdair G Kergon 
171da177e4SLinus Torvalds static LIST_HEAD(_targets);
181da177e4SLinus Torvalds static DECLARE_RWSEM(_lock);
191da177e4SLinus Torvalds 
2045194e4fSCheng Renquan static inline struct target_type *__find_target_type(const char *name)
211da177e4SLinus Torvalds {
2245194e4fSCheng Renquan 	struct target_type *tt;
231da177e4SLinus Torvalds 
2445194e4fSCheng Renquan 	list_for_each_entry(tt, &_targets, list)
2545194e4fSCheng Renquan 		if (!strcmp(name, tt->name))
2645194e4fSCheng Renquan 			return tt;
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds 	return NULL;
291da177e4SLinus Torvalds }
301da177e4SLinus Torvalds 
3145194e4fSCheng Renquan static struct target_type *get_target_type(const char *name)
321da177e4SLinus Torvalds {
3345194e4fSCheng Renquan 	struct target_type *tt;
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds 	down_read(&_lock);
361da177e4SLinus Torvalds 
3745194e4fSCheng Renquan 	tt = __find_target_type(name);
3845194e4fSCheng Renquan 	if (tt && !try_module_get(tt->module))
3945194e4fSCheng Renquan 		tt = NULL;
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds 	up_read(&_lock);
4245194e4fSCheng Renquan 	return tt;
431da177e4SLinus Torvalds }
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds static void load_module(const char *name)
461da177e4SLinus Torvalds {
471da177e4SLinus Torvalds 	request_module("dm-%s", name);
481da177e4SLinus Torvalds }
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds struct target_type *dm_get_target_type(const char *name)
511da177e4SLinus Torvalds {
5245194e4fSCheng Renquan 	struct target_type *tt = get_target_type(name);
531da177e4SLinus Torvalds 
5445194e4fSCheng Renquan 	if (!tt) {
551da177e4SLinus Torvalds 		load_module(name);
5645194e4fSCheng Renquan 		tt = get_target_type(name);
571da177e4SLinus Torvalds 	}
581da177e4SLinus Torvalds 
5945194e4fSCheng Renquan 	return tt;
601da177e4SLinus Torvalds }
611da177e4SLinus Torvalds 
6245194e4fSCheng Renquan void dm_put_target_type(struct target_type *tt)
631da177e4SLinus Torvalds {
641da177e4SLinus Torvalds 	down_read(&_lock);
6545194e4fSCheng Renquan 	module_put(tt->module);
661da177e4SLinus Torvalds 	up_read(&_lock);
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds int dm_target_iterate(void (*iter_func)(struct target_type *tt,
701da177e4SLinus Torvalds 					void *param), void *param)
711da177e4SLinus Torvalds {
7245194e4fSCheng Renquan 	struct target_type *tt;
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds 	down_read(&_lock);
7545194e4fSCheng Renquan 	list_for_each_entry(tt, &_targets, list)
7645194e4fSCheng Renquan 		iter_func(tt, param);
771da177e4SLinus Torvalds 	up_read(&_lock);
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds 	return 0;
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds 
8245194e4fSCheng Renquan int dm_register_target(struct target_type *tt)
831da177e4SLinus Torvalds {
841da177e4SLinus Torvalds 	int rv = 0;
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds 	down_write(&_lock);
8745194e4fSCheng Renquan 	if (__find_target_type(tt->name))
881da177e4SLinus Torvalds 		rv = -EEXIST;
891da177e4SLinus Torvalds 	else
9045194e4fSCheng Renquan 		list_add(&tt->list, &_targets);
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds 	up_write(&_lock);
931da177e4SLinus Torvalds 	return rv;
941da177e4SLinus Torvalds }
951da177e4SLinus Torvalds 
9645194e4fSCheng Renquan void dm_unregister_target(struct target_type *tt)
971da177e4SLinus Torvalds {
981da177e4SLinus Torvalds 	down_write(&_lock);
9945194e4fSCheng Renquan 	if (!__find_target_type(tt->name)) {
10045194e4fSCheng Renquan 		DMCRIT("Unregistering unrecognised target: %s", tt->name);
10110d3bd09SMikulas Patocka 		BUG();
1021da177e4SLinus Torvalds 	}
1031da177e4SLinus Torvalds 
10445194e4fSCheng Renquan 	list_del(&tt->list);
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds 	up_write(&_lock);
1071da177e4SLinus Torvalds }
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds /*
1101da177e4SLinus Torvalds  * io-err: always fails an io, useful for bringing
1111da177e4SLinus Torvalds  * up LVs that have holes in them.
1121da177e4SLinus Torvalds  */
11345194e4fSCheng Renquan static int io_err_ctr(struct dm_target *tt, unsigned int argc, char **args)
1141da177e4SLinus Torvalds {
11538e1b257SMike Snitzer 	/*
11638e1b257SMike Snitzer 	 * Return error for discards instead of -EOPNOTSUPP
11738e1b257SMike Snitzer 	 */
11855a62eefSAlasdair G Kergon 	tt->num_discard_bios = 1;
11938e1b257SMike Snitzer 
1201da177e4SLinus Torvalds 	return 0;
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds 
12345194e4fSCheng Renquan static void io_err_dtr(struct dm_target *tt)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds 	/* empty */
1261da177e4SLinus Torvalds }
1271da177e4SLinus Torvalds 
1287de3ee57SMikulas Patocka static int io_err_map(struct dm_target *tt, struct bio *bio)
1291da177e4SLinus Torvalds {
130846785e6SChristoph Hellwig 	return DM_MAPIO_KILL;
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds 
133e5863d9aSMike Snitzer static int io_err_clone_and_map_rq(struct dm_target *ti, struct request *rq,
134e5863d9aSMike Snitzer 				   union map_info *map_context,
135e5863d9aSMike Snitzer 				   struct request **clone)
136e5863d9aSMike Snitzer {
137412445acSChristoph Hellwig 	return DM_MAPIO_KILL;
138e5863d9aSMike Snitzer }
139e5863d9aSMike Snitzer 
1405de719e3SYufen Yu static void io_err_release_clone_rq(struct request *clone,
1415de719e3SYufen Yu 				    union map_info *map_context)
142e5863d9aSMike Snitzer {
143e5863d9aSMike Snitzer }
144e5863d9aSMike Snitzer 
145817bf402SDan Williams static long io_err_dax_direct_access(struct dm_target *ti, pgoff_t pgoff,
146*e511c4a3SJane Chu 		long nr_pages, enum dax_access_mode mode, void **kaddr,
147*e511c4a3SJane Chu 		pfn_t *pfn)
148f8df1fdfSMike Snitzer {
149f8df1fdfSMike Snitzer 	return -EIO;
150f8df1fdfSMike Snitzer }
151f8df1fdfSMike Snitzer 
1521da177e4SLinus Torvalds static struct target_type error_target = {
1531da177e4SLinus Torvalds 	.name = "error",
154f8df1fdfSMike Snitzer 	.version = {1, 5, 0},
155f083b09bSMike Snitzer 	.features = DM_TARGET_WILDCARD,
1561da177e4SLinus Torvalds 	.ctr  = io_err_ctr,
1571da177e4SLinus Torvalds 	.dtr  = io_err_dtr,
1581da177e4SLinus Torvalds 	.map  = io_err_map,
159e5863d9aSMike Snitzer 	.clone_and_map_rq = io_err_clone_and_map_rq,
160e5863d9aSMike Snitzer 	.release_clone_rq = io_err_release_clone_rq,
161817bf402SDan Williams 	.direct_access = io_err_dax_direct_access,
1621da177e4SLinus Torvalds };
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds int __init dm_target_init(void)
1651da177e4SLinus Torvalds {
1661da177e4SLinus Torvalds 	return dm_register_target(&error_target);
1671da177e4SLinus Torvalds }
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds void dm_target_exit(void)
1701da177e4SLinus Torvalds {
17110d3bd09SMikulas Patocka 	dm_unregister_target(&error_target);
1721da177e4SLinus Torvalds }
1731da177e4SLinus Torvalds 
1741da177e4SLinus Torvalds EXPORT_SYMBOL(dm_register_target);
1751da177e4SLinus Torvalds EXPORT_SYMBOL(dm_unregister_target);
176