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