1 /* 2 * Copyright (C) 2003 Sistina Software. 3 * Copyright (C) 2004 Red Hat, Inc. All rights reserved. 4 * 5 * Module Author: Heinz Mauelshagen 6 * 7 * This file is released under the GPL. 8 * 9 * Path selector registration. 10 */ 11 12 #include <linux/device-mapper.h> 13 14 #include "dm-path-selector.h" 15 16 #include <linux/slab.h> 17 18 struct ps_internal { 19 struct path_selector_type pst; 20 21 struct list_head list; 22 long use; 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) { 49 if ((psi->use == 0) && !try_module_get(psi->pst.module)) 50 psi = NULL; 51 else 52 psi->use++; 53 } 54 up_read(&_ps_lock); 55 56 return psi; 57 } 58 59 struct path_selector_type *dm_get_path_selector(const char *name) 60 { 61 struct ps_internal *psi; 62 63 if (!name) 64 return NULL; 65 66 psi = get_path_selector(name); 67 if (!psi) { 68 request_module("dm-%s", name); 69 psi = get_path_selector(name); 70 } 71 72 return psi ? &psi->pst : NULL; 73 } 74 75 void dm_put_path_selector(struct path_selector_type *pst) 76 { 77 struct ps_internal *psi; 78 79 if (!pst) 80 return; 81 82 down_read(&_ps_lock); 83 psi = __find_path_selector_type(pst->name); 84 if (!psi) 85 goto out; 86 87 if (--psi->use == 0) 88 module_put(psi->pst.module); 89 90 BUG_ON(psi->use < 0); 91 92 out: 93 up_read(&_ps_lock); 94 } 95 96 static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst) 97 { 98 struct ps_internal *psi = kzalloc(sizeof(*psi), GFP_KERNEL); 99 100 if (psi) 101 psi->pst = *pst; 102 103 return psi; 104 } 105 106 int dm_register_path_selector(struct path_selector_type *pst) 107 { 108 int r = 0; 109 struct ps_internal *psi = _alloc_path_selector(pst); 110 111 if (!psi) 112 return -ENOMEM; 113 114 down_write(&_ps_lock); 115 116 if (__find_path_selector_type(pst->name)) { 117 kfree(psi); 118 r = -EEXIST; 119 } else 120 list_add(&psi->list, &_path_selectors); 121 122 up_write(&_ps_lock); 123 124 return r; 125 } 126 127 int dm_unregister_path_selector(struct path_selector_type *pst) 128 { 129 struct ps_internal *psi; 130 131 down_write(&_ps_lock); 132 133 psi = __find_path_selector_type(pst->name); 134 if (!psi) { 135 up_write(&_ps_lock); 136 return -EINVAL; 137 } 138 139 if (psi->use) { 140 up_write(&_ps_lock); 141 return -ETXTBSY; 142 } 143 144 list_del(&psi->list); 145 146 up_write(&_ps_lock); 147 148 kfree(psi); 149 150 return 0; 151 } 152 153 EXPORT_SYMBOL_GPL(dm_register_path_selector); 154 EXPORT_SYMBOL_GPL(dm_unregister_path_selector); 155