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(sem: &_ps_lock); |
47 | psi = __find_path_selector_type(name); |
48 | if (psi && !try_module_get(module: psi->pst.module)) |
49 | psi = NULL; |
50 | up_read(sem: &_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(sem: &_ps_lock); |
79 | psi = __find_path_selector_type(name: pst->name); |
80 | if (!psi) |
81 | goto out; |
82 | |
83 | module_put(module: psi->pst.module); |
84 | out: |
85 | up_read(sem: &_ps_lock); |
86 | } |
87 | |
88 | static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst) |
89 | { |
90 | struct ps_internal *psi = kzalloc(size: 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(sem: &_ps_lock); |
107 | |
108 | if (__find_path_selector_type(name: pst->name)) { |
109 | kfree(objp: psi); |
110 | r = -EEXIST; |
111 | } else |
112 | list_add(new: &psi->list, head: &_path_selectors); |
113 | |
114 | up_write(sem: &_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(sem: &_ps_lock); |
125 | |
126 | psi = __find_path_selector_type(name: pst->name); |
127 | if (!psi) { |
128 | up_write(sem: &_ps_lock); |
129 | return -EINVAL; |
130 | } |
131 | |
132 | list_del(entry: &psi->list); |
133 | |
134 | up_write(sem: &_ps_lock); |
135 | |
136 | kfree(objp: psi); |
137 | |
138 | return 0; |
139 | } |
140 | EXPORT_SYMBOL_GPL(dm_unregister_path_selector); |
141 |