Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | ||
586e80e6 MP |
12 | #include <linux/device-mapper.h> |
13 | ||
1da177e4 LT |
14 | #include "dm-path-selector.h" |
15 | ||
16 | #include <linux/slab.h> | |
17 | ||
18 | struct ps_internal { | |
19 | struct path_selector_type pst; | |
1da177e4 | 20 | struct list_head list; |
1da177e4 LT |
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 | ||
5e198d94 | 28 | static struct ps_internal *__find_path_selector_type(const char *name) |
1da177e4 LT |
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); | |
aea90588 JN |
46 | if (psi && !try_module_get(psi->pst.module)) |
47 | psi = NULL; | |
1da177e4 LT |
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 | ||
aea90588 | 81 | module_put(psi->pst.module); |
1da177e4 LT |
82 | out: |
83 | up_read(&_ps_lock); | |
84 | } | |
85 | ||
86 | static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst) | |
87 | { | |
094262db | 88 | struct ps_internal *psi = kzalloc(sizeof(*psi), GFP_KERNEL); |
1da177e4 | 89 | |
094262db | 90 | if (psi) |
1da177e4 | 91 | psi->pst = *pst; |
1da177e4 LT |
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 | ||
1da177e4 LT |
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); |