1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2003 Sistina Software. 4 * Copyright (C) 2004 Red Hat, Inc. All rights reserved. 5 * 6 * Module Author: Heinz Mauelshagen 7 * 8 * This file is released under the GPL. 9 * 10 * Path selector registration. 11 */ 12 13 #include <linux/device-mapper.h> 14 #include <linux/module.h> 15 16 #include "dm-path-selector.h" 17 18 #include <linux/slab.h> 19 20 struct ps_internal { 21 struct path_selector_type pst; 22 struct list_head list; 23 }; 24 25 #define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst) 26 27 static LIST_HEAD(_path_selectors); 28 static DECLARE_RWSEM(_ps_lock); 29 30 static struct ps_internal *__find_path_selector_type(const char *name) 31 { 32 struct ps_internal *psi; 33 34 list_for_each_entry(psi, &_path_selectors, list) { 35 if (!strcmp(name, psi->pst.name)) 36 return psi; 37 } 38 39 return NULL; 40 } 41 42 static struct ps_internal *get_path_selector(const char *name) 43 { 44 struct ps_internal *psi; 45 46 down_read(&_ps_lock); 47 psi = __find_path_selector_type(name); 48 if (psi && !try_module_get(psi->pst.module)) 49 psi = NULL; 50 up_read(&_ps_lock); 51 52 return psi; 53 } 54 55 struct path_selector_type *dm_get_path_selector(const char *name) 56 { 57 struct ps_internal *psi; 58 59 if (!name) 60 return NULL; 61 62 psi = get_path_selector(name); 63 if (!psi) { 64 request_module("dm-%s", name); 65 psi = get_path_selector(name); 66 } 67 68 return psi ? &psi->pst : NULL; 69 } 70 71 void dm_put_path_selector(struct path_selector_type *pst) 72 { 73 struct ps_internal *psi; 74 75 if (!pst) 76 return; 77 78 down_read(&_ps_lock); 79 psi = __find_path_selector_type(pst->name); 80 if (!psi) 81 goto out; 82 83 module_put(psi->pst.module); 84 out: 85 up_read(&_ps_lock); 86 } 87 88 static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst) 89 { 90 struct ps_internal *psi = kzalloc(sizeof(*psi), GFP_KERNEL); 91 92 if (psi) 93 psi->pst = *pst; 94 95 return psi; 96 } 97 98 int dm_register_path_selector(struct path_selector_type *pst) 99 { 100 int r = 0; 101 struct ps_internal *psi = _alloc_path_selector(pst); 102 103 if (!psi) 104 return -ENOMEM; 105 106 down_write(&_ps_lock); 107 108 if (__find_path_selector_type(pst->name)) { 109 kfree(psi); 110 r = -EEXIST; 111 } else 112 list_add(&psi->list, &_path_selectors); 113 114 up_write(&_ps_lock); 115 116 return r; 117 } 118 EXPORT_SYMBOL_GPL(dm_register_path_selector); 119 120 int dm_unregister_path_selector(struct path_selector_type *pst) 121 { 122 struct ps_internal *psi; 123 124 down_write(&_ps_lock); 125 126 psi = __find_path_selector_type(pst->name); 127 if (!psi) { 128 up_write(&_ps_lock); 129 return -EINVAL; 130 } 131 132 list_del(&psi->list); 133 134 up_write(&_ps_lock); 135 136 kfree(psi); 137 138 return 0; 139 } 140 EXPORT_SYMBOL_GPL(dm_unregister_path_selector); 141