1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3 * fs/sharefs/config.c
4 *
5 * Copyright (c) 2023 Huawei Device Co., Ltd.
6 */
7
8 #include <linux/configfs.h>
9 #include <linux/ctype.h>
10 #include <linux/dcache.h>
11 #include <linux/hashtable.h>
12 #include <linux/slab.h>
13 #include "sharefs.h"
14
15 static struct kmem_cache *sharefs_bid_entry_cachep;
16
17 struct sharefs_bid_entry {
18 struct hlist_node node;
19 struct qstr str;
20 int id;
21 };
22
23 struct sharefs_config_bitem {
24 struct config_item item;
25 struct qstr str;
26 };
27
make_hash(const char *name, unsigned int len)28 static unsigned int make_hash(const char *name, unsigned int len)
29 {
30 unsigned long hash;
31
32 hash = init_name_hash(0);
33 while (len--)
34 hash = partial_name_hash(tolower(*name++), hash);
35
36 return end_name_hash(hash);
37 }
38
make_qstr(const char *name)39 static struct qstr make_qstr(const char *name)
40 {
41 struct qstr str;
42 str.name = name;
43 str.len = strlen(name);
44 str.hash = make_hash(str.name, str.len);
45
46 return str;
47 }
48
alloc_bid_entry(const char *name, int id)49 static struct sharefs_bid_entry *alloc_bid_entry(const char *name, int id)
50 {
51 struct sharefs_bid_entry *bid_entry;
52 char *bid_entry_name;
53
54 bid_entry = kmem_cache_alloc(sharefs_bid_entry_cachep, GFP_KERNEL);
55 if (!bid_entry) {
56 bid_entry = ERR_PTR(-ENOMEM);
57 goto out;
58 }
59
60 bid_entry_name = kstrdup(name, GFP_KERNEL);
61 if (!bid_entry_name) {
62 kmem_cache_free(sharefs_bid_entry_cachep, bid_entry);
63 bid_entry = ERR_PTR(-ENOMEM);
64 goto out;
65 }
66
67 INIT_HLIST_NODE(&bid_entry->node);
68 bid_entry->str = make_qstr(bid_entry_name);
69 bid_entry->id = id;
70 out:
71 return bid_entry;
72 }
73
free_bid_entry(struct sharefs_bid_entry *bid_entry)74 static void free_bid_entry(struct sharefs_bid_entry *bid_entry)
75 {
76 if (bid_entry == NULL)
77 return;
78
79 kfree(bid_entry->str.name);
80 kmem_cache_free(sharefs_bid_entry_cachep, bid_entry);
81 }
82
alloc_bitem(const char *name)83 static struct sharefs_config_bitem *alloc_bitem(const char *name)
84 {
85 struct sharefs_config_bitem *bitem;
86 char *bitem_name;
87
88 bitem = kzalloc(sizeof(*bitem), GFP_KERNEL);
89 if (!bitem) {
90 bitem = ERR_PTR(-ENOMEM);
91 goto out;
92 }
93
94 bitem_name = kstrdup(name, GFP_KERNEL);
95 if (!bitem_name) {
96 kfree(bitem);
97 bitem = ERR_PTR(-ENOMEM);
98 goto out;
99 }
100
101 bitem->str = make_qstr(bitem_name);
102 out:
103 return bitem;
104 }
105
free_bitem(struct sharefs_config_bitem *bitem)106 static void free_bitem(struct sharefs_config_bitem *bitem)
107 {
108 if (bitem == NULL)
109 return;
110
111 kfree(bitem->str.name);
112 kfree(bitem);
113 }
114
115 #define SHAREFS_BUNDLE_ATTRIBUTE(_attr_) \
116 \
117 static DEFINE_HASHTABLE(sharefs_##_attr_##_hash_table, 4); \
118 \
119 static DEFINE_MUTEX(sharefs_##_attr_##_hash_mutex); \
120 \
121 static int query_##_attr_##_hash_entry(struct qstr *str) \
122 { \
123 int id = 0; \
124 struct sharefs_bid_entry *bid_entry; \
125 struct hlist_node *hash_node; \
126 \
127 mutex_lock(&sharefs_##_attr_##_hash_mutex); \
128 hash_for_each_possible_safe(sharefs_##_attr_##_hash_table, \
129 bid_entry, hash_node, node, str->hash) { \
130 if (qstr_case_eq(str, &bid_entry->str)) { \
131 id = bid_entry->id; \
132 break; \
133 } \
134 } \
135 mutex_unlock(&sharefs_##_attr_##_hash_mutex); \
136 \
137 return id; \
138 } \
139 \
140 static int insert_##_attr_##_hash_entry(struct qstr *str, int id) \
141 { \
142 int err = 0; \
143 struct sharefs_bid_entry *bid_entry; \
144 struct hlist_node *hash_node; \
145 \
146 sharefs_info("insert name = %s", str->name); \
147 \
148 mutex_lock(&sharefs_##_attr_##_hash_mutex); \
149 hash_for_each_possible_safe(sharefs_##_attr_##_hash_table, \
150 bid_entry, hash_node, node, str->hash) { \
151 if (qstr_case_eq(str, &bid_entry->str)) { \
152 bid_entry->id = id; \
153 mutex_unlock(&sharefs_##_attr_##_hash_mutex); \
154 goto out; \
155 } \
156 } \
157 mutex_unlock(&sharefs_##_attr_##_hash_mutex); \
158 \
159 bid_entry = alloc_bid_entry(str->name, id); \
160 if (IS_ERR(bid_entry)) { \
161 err = PTR_ERR(bid_entry); \
162 goto out; \
163 } \
164 \
165 hash_add_rcu(sharefs_##_attr_##_hash_table, &bid_entry->node, \
166 bid_entry->str.hash); \
167 out: \
168 return err; \
169 } \
170 \
171 static void remove_##_attr_##_hash_entry(struct qstr *str) \
172 { \
173 struct sharefs_bid_entry *bid_entry; \
174 struct hlist_node *hash_node; \
175 \
176 sharefs_info("remove name = %s", str->name); \
177 \
178 mutex_lock(&sharefs_##_attr_##_hash_mutex); \
179 hash_for_each_possible_safe(sharefs_##_attr_##_hash_table, \
180 bid_entry, hash_node, node, str->hash) { \
181 if (qstr_case_eq(str, &bid_entry->str)) { \
182 hash_del_rcu(&bid_entry->node); \
183 free_bid_entry(bid_entry); \
184 break; \
185 } \
186 } \
187 mutex_unlock(&sharefs_##_attr_##_hash_mutex); \
188 } \
189 \
190 static void clear_##_attr_##_hash_entry(void) \
191 { \
192 int index; \
193 struct sharefs_bid_entry *bid_entry; \
194 struct hlist_node *hash_node; \
195 \
196 sharefs_info("clear bid entry"); \
197 \
198 mutex_lock(&sharefs_##_attr_##_hash_mutex); \
199 hash_for_each_safe(sharefs_##_attr_##_hash_table, index, \
200 hash_node, bid_entry, node) { \
201 hash_del_rcu(&bid_entry->node); \
202 kfree(bid_entry->str.name); \
203 kmem_cache_free(sharefs_bid_entry_cachep, bid_entry); \
204 } \
205 mutex_unlock(&sharefs_##_attr_##_hash_mutex); \
206 } \
207 \
208 static int sharefs_##_attr_##_get(const char *bname) \
209 { \
210 struct qstr str; \
211 \
212 str = make_qstr(bname); \
213 return query_##_attr_##_hash_entry(&str); \
214 } \
215 \
216 static ssize_t sharefs_##_attr_##_show(struct config_item *item, \
217 char *page) \
218 { \
219 int id; \
220 struct sharefs_config_bitem *bitem; \
221 \
222 sharefs_info("show bundle id"); \
223 \
224 bitem = container_of(item, struct sharefs_config_bitem, item); \
225 id = query_##_attr_##_hash_entry(&bitem->str); \
226 \
227 return scnprintf(page, PAGE_SIZE, "%u\n", id); \
228 } \
229 \
230 static ssize_t sharefs_##_attr_##_store(struct config_item *item, \
231 const char *page, size_t count) \
232 { \
233 int id; \
234 int err; \
235 size_t size; \
236 struct sharefs_config_bitem *bitem; \
237 \
238 sharefs_info("store bundle id"); \
239 \
240 bitem = container_of(item, struct sharefs_config_bitem, item); \
241 \
242 if (kstrtouint(page, 10, &id)) { \
243 size = -EINVAL; \
244 goto out; \
245 } \
246 \
247 err = insert_##_attr_##_hash_entry(&bitem->str, id); \
248 if (err) { \
249 size = err; \
250 goto out; \
251 } \
252 \
253 size = count; \
254 out: \
255 return size; \
256 } \
257 \
258 static struct configfs_attribute sharefs_##_attr_##_attr = { \
259 .ca_name = __stringify(_attr_), \
260 .ca_mode = S_IRUGO | S_IWUGO, \
261 .ca_owner = THIS_MODULE, \
262 .show = sharefs_##_attr_##_show, \
263 .store = sharefs_##_attr_##_store, \
264 };
265
266 SHAREFS_BUNDLE_ATTRIBUTE(appid)
267
268 static struct configfs_attribute *sharefs_battrs[] = {
269 &sharefs_appid_attr,
270 NULL,
271 };
272
sharefs_config_bitem_release(struct config_item *item)273 static void sharefs_config_bitem_release(struct config_item *item)
274 {
275 struct sharefs_config_bitem *bitem;
276
277 sharefs_info("release bundle item");
278
279 bitem = container_of(item, struct sharefs_config_bitem, item);
280 remove_appid_hash_entry(&bitem->str);
281 remove_appid_hash_entry(&bitem->str);
282 free_bitem(bitem);
283 }
284
285 static struct configfs_item_operations sharefs_config_bitem_ops = {
286 .release = sharefs_config_bitem_release,
287 };
288
289 static struct config_item_type sharefs_config_bitem_type = {
290 .ct_item_ops = &sharefs_config_bitem_ops,
291 .ct_attrs = sharefs_battrs,
292 .ct_owner = THIS_MODULE,
293 };
294
sharefs_make_bitem(struct config_group *group, const char *name)295 static struct config_item *sharefs_make_bitem(struct config_group *group,
296 const char *name)
297 {
298 struct config_item *item;
299 struct sharefs_config_bitem *bitem;
300
301 bitem = alloc_bitem(name);
302 if (IS_ERR(bitem)) {
303 item = ERR_PTR(-ENOMEM);
304 goto out;
305 }
306
307 config_item_init_type_name(&bitem->item, name,
308 &sharefs_config_bitem_type);
309 item = &bitem->item;
310 out:
311 return item;
312 }
313
314 static struct configfs_group_operations sharefs_group_ops = {
315 .make_item = sharefs_make_bitem,
316 };
317
318 static struct config_item_type sharefs_group_type = {
319 .ct_group_ops = &sharefs_group_ops,
320 .ct_owner = THIS_MODULE,
321 };
322
323 static struct configfs_subsystem sharefs_subsystem = {
324 .su_group = {
325 .cg_item = {
326 .ci_namebuf = "sharefs",
327 .ci_type = &sharefs_group_type,
328 },
329 },
330 };
331
get_bid_config(const char *bname)332 int get_bid_config(const char *bname)
333 {
334 return sharefs_appid_get(bname);
335 }
336
sharefs_init_configfs(void)337 int __init sharefs_init_configfs(void)
338 {
339 int err;
340 struct configfs_subsystem *subsys;
341
342 sharefs_info("init configfs");
343
344 sharefs_bid_entry_cachep = kmem_cache_create("sharefs_bid_entry_cachep",
345 sizeof(struct sharefs_bid_entry), 0, 0, NULL);
346 if (!sharefs_bid_entry_cachep) {
347 sharefs_err("failed to create bid entry cachep");
348 err = -ENOMEM;
349 goto out;
350 }
351
352 subsys = &sharefs_subsystem;
353 config_group_init(&subsys->su_group);
354 mutex_init(&subsys->su_mutex);
355
356 err = configfs_register_subsystem(subsys);
357 if (err)
358 sharefs_err("failed to register subsystem");
359
360 out:
361 return err;
362 }
363
sharefs_exit_configfs(void)364 void sharefs_exit_configfs(void)
365 {
366 sharefs_info("sharefs exit configfs");
367
368 configfs_unregister_subsystem(&sharefs_subsystem);
369 clear_appid_hash_entry();
370
371 kmem_cache_destroy(sharefs_bid_entry_cachep);
372 }