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 struct list_head list; 21 }; 22 23 #define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst) 24 25 static LIST_HEAD(_path_selectors); 26 static DECLARE_RWSEM(_ps_lock); 27 28 static struct ps_internal *__find_path_selector_type(const char *name) 29 { 30 struct ps_internal *psi; 31 32 list_for_each_entry(psi, &_path_selectors, list) { 33 if (!strcmp(name, psi->pst.name)) 34 return psi; 35 } 36 37 return NULL; 38 } 39 40 static struct ps_internal *get_path_selector(const char *name) 41 { 42 struct ps_internal *psi; 43 44 down_read(&_ps_lock); 45 psi = __find_path_selector_type(name); 46 if (psi && !try_module_get(psi->pst.module)) 47 psi = NULL; 48 up_read(&_ps_lock); 49 50 return psi; 51 } 52 53 struct path_selector_type *dm_get_path_selector(const char *name) 54 { 55 struct ps_internal *psi; 56 57 if (!name) 58 return NULL; 59 60 psi = get_path_selector(name); 61 if (!psi) { 62 request_module("dm-%s", name); 63 psi = get_path_selector(name); 64 } 65 66 return psi ? &psi->pst : NULL; 67 } 68 69 void dm_put_path_selector(struct path_selector_type *pst) 70 { 71 struct ps_internal *psi; 72 73 if (!pst) 74 return; 75 76 down_read(&_ps_lock); 77 psi = __find_path_selector_type(pst->name); 78 if (!psi) 79 goto out; 80 81 module_put(psi->pst.module); 82 out: 83 up_read(&_ps_lock); 84 } 85 86 static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst) 87 { 88 struct ps_internal *psi = kzalloc(sizeof(*psi), GFP_KERNEL); 89 90 if (psi) 91 psi->pst = *pst; 92 93 return psi; 94 } 95 96 int dm_register_path_selector(struct path_selector_type *pst) 97 { 98 int r = 0; 99 struct ps_internal *psi = _alloc_path_selector(pst); 100 101 if (!psi) 102 return -ENOMEM; 103 104 down_write(&_ps_lock); 105 106 if (__find_path_selector_type(pst->name)) { 107 kfree(psi); 108 r = -EEXIST; 109 } else 110 list_add(&psi->list, &_path_selectors); 111 112 up_write(&_ps_lock); 113 114 return r; 115 } 116 117 int dm_unregister_path_selector(struct path_selector_type *pst) 118 { 119 struct ps_internal *psi; 120 121 down_write(&_ps_lock); 122 123 psi = __find_path_selector_type(pst->name); 124 if (!psi) { 125 up_write(&_ps_lock); 126 return -EINVAL; 127 } 128 129 list_del(&psi->list); 130 131 up_write(&_ps_lock); 132 133 kfree(psi); 134 135 return 0; 136 } 137 138 EXPORT_SYMBOL_GPL(dm_register_path_selector); 139 EXPORT_SYMBOL_GPL(dm_unregister_path_selector); 140