18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (C) 2001 Sistina Software (UK) Limited
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is released under the GPL.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "dm-core.h"
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/kmod.h>
128c2ecf20Sopenharmony_ci#include <linux/bio.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define DM_MSG_PREFIX "target"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic LIST_HEAD(_targets);
178c2ecf20Sopenharmony_cistatic DECLARE_RWSEM(_lock);
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic inline struct target_type *__find_target_type(const char *name)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	struct target_type *tt;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	list_for_each_entry(tt, &_targets, list)
248c2ecf20Sopenharmony_ci		if (!strcmp(name, tt->name))
258c2ecf20Sopenharmony_ci			return tt;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	return NULL;
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic struct target_type *get_target_type(const char *name)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	struct target_type *tt;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	down_read(&_lock);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	tt = __find_target_type(name);
378c2ecf20Sopenharmony_ci	if (tt && !try_module_get(tt->module))
388c2ecf20Sopenharmony_ci		tt = NULL;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	up_read(&_lock);
418c2ecf20Sopenharmony_ci	return tt;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic void load_module(const char *name)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	request_module("dm-%s", name);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistruct target_type *dm_get_target_type(const char *name)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct target_type *tt = get_target_type(name);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	if (!tt) {
548c2ecf20Sopenharmony_ci		load_module(name);
558c2ecf20Sopenharmony_ci		tt = get_target_type(name);
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	return tt;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_civoid dm_put_target_type(struct target_type *tt)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	down_read(&_lock);
648c2ecf20Sopenharmony_ci	module_put(tt->module);
658c2ecf20Sopenharmony_ci	up_read(&_lock);
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ciint dm_target_iterate(void (*iter_func)(struct target_type *tt,
698c2ecf20Sopenharmony_ci					void *param), void *param)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	struct target_type *tt;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	down_read(&_lock);
748c2ecf20Sopenharmony_ci	list_for_each_entry(tt, &_targets, list)
758c2ecf20Sopenharmony_ci		iter_func(tt, param);
768c2ecf20Sopenharmony_ci	up_read(&_lock);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	return 0;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ciint dm_register_target(struct target_type *tt)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	int rv = 0;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	down_write(&_lock);
868c2ecf20Sopenharmony_ci	if (__find_target_type(tt->name))
878c2ecf20Sopenharmony_ci		rv = -EEXIST;
888c2ecf20Sopenharmony_ci	else
898c2ecf20Sopenharmony_ci		list_add(&tt->list, &_targets);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	up_write(&_lock);
928c2ecf20Sopenharmony_ci	return rv;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_civoid dm_unregister_target(struct target_type *tt)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	down_write(&_lock);
988c2ecf20Sopenharmony_ci	if (!__find_target_type(tt->name)) {
998c2ecf20Sopenharmony_ci		DMCRIT("Unregistering unrecognised target: %s", tt->name);
1008c2ecf20Sopenharmony_ci		BUG();
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	list_del(&tt->list);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	up_write(&_lock);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci/*
1098c2ecf20Sopenharmony_ci * io-err: always fails an io, useful for bringing
1108c2ecf20Sopenharmony_ci * up LVs that have holes in them.
1118c2ecf20Sopenharmony_ci */
1128c2ecf20Sopenharmony_cistatic int io_err_ctr(struct dm_target *tt, unsigned int argc, char **args)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	/*
1158c2ecf20Sopenharmony_ci	 * Return error for discards instead of -EOPNOTSUPP
1168c2ecf20Sopenharmony_ci	 */
1178c2ecf20Sopenharmony_ci	tt->num_discard_bios = 1;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	return 0;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic void io_err_dtr(struct dm_target *tt)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	/* empty */
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic int io_err_map(struct dm_target *tt, struct bio *bio)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	return DM_MAPIO_KILL;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic int io_err_clone_and_map_rq(struct dm_target *ti, struct request *rq,
1338c2ecf20Sopenharmony_ci				   union map_info *map_context,
1348c2ecf20Sopenharmony_ci				   struct request **clone)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	return DM_MAPIO_KILL;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic void io_err_release_clone_rq(struct request *clone,
1408c2ecf20Sopenharmony_ci				    union map_info *map_context)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic long io_err_dax_direct_access(struct dm_target *ti, pgoff_t pgoff,
1458c2ecf20Sopenharmony_ci		long nr_pages, void **kaddr, pfn_t *pfn)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	return -EIO;
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic struct target_type error_target = {
1518c2ecf20Sopenharmony_ci	.name = "error",
1528c2ecf20Sopenharmony_ci	.version = {1, 5, 0},
1538c2ecf20Sopenharmony_ci	.features = DM_TARGET_WILDCARD,
1548c2ecf20Sopenharmony_ci	.ctr  = io_err_ctr,
1558c2ecf20Sopenharmony_ci	.dtr  = io_err_dtr,
1568c2ecf20Sopenharmony_ci	.map  = io_err_map,
1578c2ecf20Sopenharmony_ci	.clone_and_map_rq = io_err_clone_and_map_rq,
1588c2ecf20Sopenharmony_ci	.release_clone_rq = io_err_release_clone_rq,
1598c2ecf20Sopenharmony_ci	.direct_access = io_err_dax_direct_access,
1608c2ecf20Sopenharmony_ci};
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ciint __init dm_target_init(void)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	return dm_register_target(&error_target);
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_civoid dm_target_exit(void)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	dm_unregister_target(&error_target);
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_register_target);
1738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dm_unregister_target);
174