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