0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/device-mapper.h>
0013 #include <linux/module.h>
0014
0015 #include "dm-path-selector.h"
0016
0017 #include <linux/slab.h>
0018
0019 struct ps_internal {
0020 struct path_selector_type pst;
0021 struct list_head list;
0022 };
0023
0024 #define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst)
0025
0026 static LIST_HEAD(_path_selectors);
0027 static DECLARE_RWSEM(_ps_lock);
0028
0029 static struct ps_internal *__find_path_selector_type(const char *name)
0030 {
0031 struct ps_internal *psi;
0032
0033 list_for_each_entry(psi, &_path_selectors, list) {
0034 if (!strcmp(name, psi->pst.name))
0035 return psi;
0036 }
0037
0038 return NULL;
0039 }
0040
0041 static struct ps_internal *get_path_selector(const char *name)
0042 {
0043 struct ps_internal *psi;
0044
0045 down_read(&_ps_lock);
0046 psi = __find_path_selector_type(name);
0047 if (psi && !try_module_get(psi->pst.module))
0048 psi = NULL;
0049 up_read(&_ps_lock);
0050
0051 return psi;
0052 }
0053
0054 struct path_selector_type *dm_get_path_selector(const char *name)
0055 {
0056 struct ps_internal *psi;
0057
0058 if (!name)
0059 return NULL;
0060
0061 psi = get_path_selector(name);
0062 if (!psi) {
0063 request_module("dm-%s", name);
0064 psi = get_path_selector(name);
0065 }
0066
0067 return psi ? &psi->pst : NULL;
0068 }
0069
0070 void dm_put_path_selector(struct path_selector_type *pst)
0071 {
0072 struct ps_internal *psi;
0073
0074 if (!pst)
0075 return;
0076
0077 down_read(&_ps_lock);
0078 psi = __find_path_selector_type(pst->name);
0079 if (!psi)
0080 goto out;
0081
0082 module_put(psi->pst.module);
0083 out:
0084 up_read(&_ps_lock);
0085 }
0086
0087 static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst)
0088 {
0089 struct ps_internal *psi = kzalloc(sizeof(*psi), GFP_KERNEL);
0090
0091 if (psi)
0092 psi->pst = *pst;
0093
0094 return psi;
0095 }
0096
0097 int dm_register_path_selector(struct path_selector_type *pst)
0098 {
0099 int r = 0;
0100 struct ps_internal *psi = _alloc_path_selector(pst);
0101
0102 if (!psi)
0103 return -ENOMEM;
0104
0105 down_write(&_ps_lock);
0106
0107 if (__find_path_selector_type(pst->name)) {
0108 kfree(psi);
0109 r = -EEXIST;
0110 } else
0111 list_add(&psi->list, &_path_selectors);
0112
0113 up_write(&_ps_lock);
0114
0115 return r;
0116 }
0117
0118 int dm_unregister_path_selector(struct path_selector_type *pst)
0119 {
0120 struct ps_internal *psi;
0121
0122 down_write(&_ps_lock);
0123
0124 psi = __find_path_selector_type(pst->name);
0125 if (!psi) {
0126 up_write(&_ps_lock);
0127 return -EINVAL;
0128 }
0129
0130 list_del(&psi->list);
0131
0132 up_write(&_ps_lock);
0133
0134 kfree(psi);
0135
0136 return 0;
0137 }
0138
0139 EXPORT_SYMBOL_GPL(dm_register_path_selector);
0140 EXPORT_SYMBOL_GPL(dm_unregister_path_selector);