162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/sharefs/config.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/configfs.h> 962306a36Sopenharmony_ci#include <linux/ctype.h> 1062306a36Sopenharmony_ci#include <linux/dcache.h> 1162306a36Sopenharmony_ci#include <linux/hashtable.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include "sharefs.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic struct kmem_cache *sharefs_bid_entry_cachep; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct sharefs_bid_entry { 1862306a36Sopenharmony_ci struct hlist_node node; 1962306a36Sopenharmony_ci struct qstr str; 2062306a36Sopenharmony_ci int id; 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct sharefs_config_bitem { 2462306a36Sopenharmony_ci struct config_item item; 2562306a36Sopenharmony_ci struct qstr str; 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic unsigned int make_hash(const char *name, unsigned int len) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci unsigned long hash; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci hash = init_name_hash(0); 3362306a36Sopenharmony_ci while (len--) 3462306a36Sopenharmony_ci hash = partial_name_hash(tolower(*name++), hash); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci return end_name_hash(hash); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic struct qstr make_qstr(const char *name) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct qstr str; 4262306a36Sopenharmony_ci str.name = name; 4362306a36Sopenharmony_ci str.len = strlen(name); 4462306a36Sopenharmony_ci str.hash = make_hash(str.name, str.len); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci return str; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic struct sharefs_bid_entry *alloc_bid_entry(const char *name, int id) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct sharefs_bid_entry *bid_entry; 5262306a36Sopenharmony_ci char *bid_entry_name; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci bid_entry = kmem_cache_alloc(sharefs_bid_entry_cachep, GFP_KERNEL); 5562306a36Sopenharmony_ci if (!bid_entry) { 5662306a36Sopenharmony_ci bid_entry = ERR_PTR(-ENOMEM); 5762306a36Sopenharmony_ci goto out; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci bid_entry_name = kstrdup(name, GFP_KERNEL); 6162306a36Sopenharmony_ci if (!bid_entry_name) { 6262306a36Sopenharmony_ci kmem_cache_free(sharefs_bid_entry_cachep, bid_entry); 6362306a36Sopenharmony_ci bid_entry = ERR_PTR(-ENOMEM); 6462306a36Sopenharmony_ci goto out; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci INIT_HLIST_NODE(&bid_entry->node); 6862306a36Sopenharmony_ci bid_entry->str = make_qstr(bid_entry_name); 6962306a36Sopenharmony_ci bid_entry->id = id; 7062306a36Sopenharmony_ciout: 7162306a36Sopenharmony_ci return bid_entry; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic void free_bid_entry(struct sharefs_bid_entry *bid_entry) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci if (bid_entry == NULL) 7762306a36Sopenharmony_ci return; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci kfree(bid_entry->str.name); 8062306a36Sopenharmony_ci kmem_cache_free(sharefs_bid_entry_cachep, bid_entry); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic struct sharefs_config_bitem *alloc_bitem(const char *name) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct sharefs_config_bitem *bitem; 8662306a36Sopenharmony_ci char *bitem_name; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci bitem = kzalloc(sizeof(*bitem), GFP_KERNEL); 8962306a36Sopenharmony_ci if (!bitem) { 9062306a36Sopenharmony_ci bitem = ERR_PTR(-ENOMEM); 9162306a36Sopenharmony_ci goto out; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci bitem_name = kstrdup(name, GFP_KERNEL); 9562306a36Sopenharmony_ci if (!bitem_name) { 9662306a36Sopenharmony_ci kfree(bitem); 9762306a36Sopenharmony_ci bitem = ERR_PTR(-ENOMEM); 9862306a36Sopenharmony_ci goto out; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci bitem->str = make_qstr(bitem_name); 10262306a36Sopenharmony_ciout: 10362306a36Sopenharmony_ci return bitem; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic void free_bitem(struct sharefs_config_bitem *bitem) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci if (bitem == NULL) 10962306a36Sopenharmony_ci return; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci kfree(bitem->str.name); 11262306a36Sopenharmony_ci kfree(bitem); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#define SHAREFS_BUNDLE_ATTRIBUTE(_attr_) \ 11662306a36Sopenharmony_ci \ 11762306a36Sopenharmony_cistatic DEFINE_HASHTABLE(sharefs_##_attr_##_hash_table, 4); \ 11862306a36Sopenharmony_ci \ 11962306a36Sopenharmony_cistatic DEFINE_MUTEX(sharefs_##_attr_##_hash_mutex); \ 12062306a36Sopenharmony_ci \ 12162306a36Sopenharmony_cistatic int query_##_attr_##_hash_entry(struct qstr *str) \ 12262306a36Sopenharmony_ci{ \ 12362306a36Sopenharmony_ci int id = 0; \ 12462306a36Sopenharmony_ci struct sharefs_bid_entry *bid_entry; \ 12562306a36Sopenharmony_ci struct hlist_node *hash_node; \ 12662306a36Sopenharmony_ci \ 12762306a36Sopenharmony_ci mutex_lock(&sharefs_##_attr_##_hash_mutex); \ 12862306a36Sopenharmony_ci hash_for_each_possible_safe(sharefs_##_attr_##_hash_table, \ 12962306a36Sopenharmony_ci bid_entry, hash_node, node, str->hash) { \ 13062306a36Sopenharmony_ci if (qstr_case_eq(str, &bid_entry->str)) { \ 13162306a36Sopenharmony_ci id = bid_entry->id; \ 13262306a36Sopenharmony_ci break; \ 13362306a36Sopenharmony_ci } \ 13462306a36Sopenharmony_ci } \ 13562306a36Sopenharmony_ci mutex_unlock(&sharefs_##_attr_##_hash_mutex); \ 13662306a36Sopenharmony_ci \ 13762306a36Sopenharmony_ci return id; \ 13862306a36Sopenharmony_ci} \ 13962306a36Sopenharmony_ci \ 14062306a36Sopenharmony_cistatic int insert_##_attr_##_hash_entry(struct qstr *str, int id) \ 14162306a36Sopenharmony_ci{ \ 14262306a36Sopenharmony_ci int err = 0; \ 14362306a36Sopenharmony_ci struct sharefs_bid_entry *bid_entry; \ 14462306a36Sopenharmony_ci struct hlist_node *hash_node; \ 14562306a36Sopenharmony_ci \ 14662306a36Sopenharmony_ci sharefs_info("insert name = %s", str->name); \ 14762306a36Sopenharmony_ci \ 14862306a36Sopenharmony_ci mutex_lock(&sharefs_##_attr_##_hash_mutex); \ 14962306a36Sopenharmony_ci hash_for_each_possible_safe(sharefs_##_attr_##_hash_table, \ 15062306a36Sopenharmony_ci bid_entry, hash_node, node, str->hash) { \ 15162306a36Sopenharmony_ci if (qstr_case_eq(str, &bid_entry->str)) { \ 15262306a36Sopenharmony_ci bid_entry->id = id; \ 15362306a36Sopenharmony_ci mutex_unlock(&sharefs_##_attr_##_hash_mutex); \ 15462306a36Sopenharmony_ci goto out; \ 15562306a36Sopenharmony_ci } \ 15662306a36Sopenharmony_ci } \ 15762306a36Sopenharmony_ci mutex_unlock(&sharefs_##_attr_##_hash_mutex); \ 15862306a36Sopenharmony_ci \ 15962306a36Sopenharmony_ci bid_entry = alloc_bid_entry(str->name, id); \ 16062306a36Sopenharmony_ci if (IS_ERR(bid_entry)) { \ 16162306a36Sopenharmony_ci err = PTR_ERR(bid_entry); \ 16262306a36Sopenharmony_ci goto out; \ 16362306a36Sopenharmony_ci } \ 16462306a36Sopenharmony_ci \ 16562306a36Sopenharmony_ci hash_add_rcu(sharefs_##_attr_##_hash_table, &bid_entry->node, \ 16662306a36Sopenharmony_ci bid_entry->str.hash); \ 16762306a36Sopenharmony_ciout: \ 16862306a36Sopenharmony_ci return err; \ 16962306a36Sopenharmony_ci} \ 17062306a36Sopenharmony_ci \ 17162306a36Sopenharmony_cistatic void remove_##_attr_##_hash_entry(struct qstr *str) \ 17262306a36Sopenharmony_ci{ \ 17362306a36Sopenharmony_ci struct sharefs_bid_entry *bid_entry; \ 17462306a36Sopenharmony_ci struct hlist_node *hash_node; \ 17562306a36Sopenharmony_ci \ 17662306a36Sopenharmony_ci sharefs_info("remove name = %s", str->name); \ 17762306a36Sopenharmony_ci \ 17862306a36Sopenharmony_ci mutex_lock(&sharefs_##_attr_##_hash_mutex); \ 17962306a36Sopenharmony_ci hash_for_each_possible_safe(sharefs_##_attr_##_hash_table, \ 18062306a36Sopenharmony_ci bid_entry, hash_node, node, str->hash) { \ 18162306a36Sopenharmony_ci if (qstr_case_eq(str, &bid_entry->str)) { \ 18262306a36Sopenharmony_ci hash_del_rcu(&bid_entry->node); \ 18362306a36Sopenharmony_ci free_bid_entry(bid_entry); \ 18462306a36Sopenharmony_ci break; \ 18562306a36Sopenharmony_ci } \ 18662306a36Sopenharmony_ci } \ 18762306a36Sopenharmony_ci mutex_unlock(&sharefs_##_attr_##_hash_mutex); \ 18862306a36Sopenharmony_ci} \ 18962306a36Sopenharmony_ci \ 19062306a36Sopenharmony_cistatic void clear_##_attr_##_hash_entry(void) \ 19162306a36Sopenharmony_ci{ \ 19262306a36Sopenharmony_ci int index; \ 19362306a36Sopenharmony_ci struct sharefs_bid_entry *bid_entry; \ 19462306a36Sopenharmony_ci struct hlist_node *hash_node; \ 19562306a36Sopenharmony_ci \ 19662306a36Sopenharmony_ci sharefs_info("clear bid entry"); \ 19762306a36Sopenharmony_ci \ 19862306a36Sopenharmony_ci mutex_lock(&sharefs_##_attr_##_hash_mutex); \ 19962306a36Sopenharmony_ci hash_for_each_safe(sharefs_##_attr_##_hash_table, index, \ 20062306a36Sopenharmony_ci hash_node, bid_entry, node) { \ 20162306a36Sopenharmony_ci hash_del_rcu(&bid_entry->node); \ 20262306a36Sopenharmony_ci kfree(bid_entry->str.name); \ 20362306a36Sopenharmony_ci kmem_cache_free(sharefs_bid_entry_cachep, bid_entry); \ 20462306a36Sopenharmony_ci } \ 20562306a36Sopenharmony_ci mutex_unlock(&sharefs_##_attr_##_hash_mutex); \ 20662306a36Sopenharmony_ci} \ 20762306a36Sopenharmony_ci \ 20862306a36Sopenharmony_cistatic int sharefs_##_attr_##_get(const char *bname) \ 20962306a36Sopenharmony_ci{ \ 21062306a36Sopenharmony_ci struct qstr str; \ 21162306a36Sopenharmony_ci \ 21262306a36Sopenharmony_ci str = make_qstr(bname); \ 21362306a36Sopenharmony_ci return query_##_attr_##_hash_entry(&str); \ 21462306a36Sopenharmony_ci} \ 21562306a36Sopenharmony_ci \ 21662306a36Sopenharmony_cistatic ssize_t sharefs_##_attr_##_show(struct config_item *item, \ 21762306a36Sopenharmony_ci char *page) \ 21862306a36Sopenharmony_ci{ \ 21962306a36Sopenharmony_ci int id; \ 22062306a36Sopenharmony_ci struct sharefs_config_bitem *bitem; \ 22162306a36Sopenharmony_ci \ 22262306a36Sopenharmony_ci sharefs_info("show bundle id"); \ 22362306a36Sopenharmony_ci \ 22462306a36Sopenharmony_ci bitem = container_of(item, struct sharefs_config_bitem, item); \ 22562306a36Sopenharmony_ci id = query_##_attr_##_hash_entry(&bitem->str); \ 22662306a36Sopenharmony_ci \ 22762306a36Sopenharmony_ci return scnprintf(page, PAGE_SIZE, "%u\n", id); \ 22862306a36Sopenharmony_ci} \ 22962306a36Sopenharmony_ci \ 23062306a36Sopenharmony_cistatic ssize_t sharefs_##_attr_##_store(struct config_item *item, \ 23162306a36Sopenharmony_ci const char *page, size_t count) \ 23262306a36Sopenharmony_ci{ \ 23362306a36Sopenharmony_ci int id; \ 23462306a36Sopenharmony_ci int err; \ 23562306a36Sopenharmony_ci size_t size; \ 23662306a36Sopenharmony_ci struct sharefs_config_bitem *bitem; \ 23762306a36Sopenharmony_ci \ 23862306a36Sopenharmony_ci sharefs_info("store bundle id"); \ 23962306a36Sopenharmony_ci \ 24062306a36Sopenharmony_ci bitem = container_of(item, struct sharefs_config_bitem, item); \ 24162306a36Sopenharmony_ci \ 24262306a36Sopenharmony_ci if (kstrtouint(page, 10, &id)) { \ 24362306a36Sopenharmony_ci size = -EINVAL; \ 24462306a36Sopenharmony_ci goto out; \ 24562306a36Sopenharmony_ci } \ 24662306a36Sopenharmony_ci \ 24762306a36Sopenharmony_ci err = insert_##_attr_##_hash_entry(&bitem->str, id); \ 24862306a36Sopenharmony_ci if (err) { \ 24962306a36Sopenharmony_ci size = err; \ 25062306a36Sopenharmony_ci goto out; \ 25162306a36Sopenharmony_ci } \ 25262306a36Sopenharmony_ci \ 25362306a36Sopenharmony_ci size = count; \ 25462306a36Sopenharmony_ciout: \ 25562306a36Sopenharmony_ci return size; \ 25662306a36Sopenharmony_ci} \ 25762306a36Sopenharmony_ci \ 25862306a36Sopenharmony_cistatic struct configfs_attribute sharefs_##_attr_##_attr = { \ 25962306a36Sopenharmony_ci .ca_name = __stringify(_attr_), \ 26062306a36Sopenharmony_ci .ca_mode = S_IRUGO | S_IWUGO, \ 26162306a36Sopenharmony_ci .ca_owner = THIS_MODULE, \ 26262306a36Sopenharmony_ci .show = sharefs_##_attr_##_show, \ 26362306a36Sopenharmony_ci .store = sharefs_##_attr_##_store, \ 26462306a36Sopenharmony_ci}; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ciSHAREFS_BUNDLE_ATTRIBUTE(appid) 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic struct configfs_attribute *sharefs_battrs[] = { 26962306a36Sopenharmony_ci &sharefs_appid_attr, 27062306a36Sopenharmony_ci NULL, 27162306a36Sopenharmony_ci}; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic void sharefs_config_bitem_release(struct config_item *item) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct sharefs_config_bitem *bitem; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci sharefs_info("release bundle item"); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci bitem = container_of(item, struct sharefs_config_bitem, item); 28062306a36Sopenharmony_ci remove_appid_hash_entry(&bitem->str); 28162306a36Sopenharmony_ci remove_appid_hash_entry(&bitem->str); 28262306a36Sopenharmony_ci free_bitem(bitem); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic struct configfs_item_operations sharefs_config_bitem_ops = { 28662306a36Sopenharmony_ci .release = sharefs_config_bitem_release, 28762306a36Sopenharmony_ci}; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic struct config_item_type sharefs_config_bitem_type = { 29062306a36Sopenharmony_ci .ct_item_ops = &sharefs_config_bitem_ops, 29162306a36Sopenharmony_ci .ct_attrs = sharefs_battrs, 29262306a36Sopenharmony_ci .ct_owner = THIS_MODULE, 29362306a36Sopenharmony_ci}; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic struct config_item *sharefs_make_bitem(struct config_group *group, 29662306a36Sopenharmony_ci const char *name) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct config_item *item; 29962306a36Sopenharmony_ci struct sharefs_config_bitem *bitem; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci bitem = alloc_bitem(name); 30262306a36Sopenharmony_ci if (IS_ERR(bitem)) { 30362306a36Sopenharmony_ci item = ERR_PTR(-ENOMEM); 30462306a36Sopenharmony_ci goto out; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci config_item_init_type_name(&bitem->item, name, 30862306a36Sopenharmony_ci &sharefs_config_bitem_type); 30962306a36Sopenharmony_ci item = &bitem->item; 31062306a36Sopenharmony_ciout: 31162306a36Sopenharmony_ci return item; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic struct configfs_group_operations sharefs_group_ops = { 31562306a36Sopenharmony_ci .make_item = sharefs_make_bitem, 31662306a36Sopenharmony_ci}; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic struct config_item_type sharefs_group_type = { 31962306a36Sopenharmony_ci .ct_group_ops = &sharefs_group_ops, 32062306a36Sopenharmony_ci .ct_owner = THIS_MODULE, 32162306a36Sopenharmony_ci}; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic struct configfs_subsystem sharefs_subsystem = { 32462306a36Sopenharmony_ci .su_group = { 32562306a36Sopenharmony_ci .cg_item = { 32662306a36Sopenharmony_ci .ci_namebuf = "sharefs", 32762306a36Sopenharmony_ci .ci_type = &sharefs_group_type, 32862306a36Sopenharmony_ci }, 32962306a36Sopenharmony_ci }, 33062306a36Sopenharmony_ci}; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ciint get_bid_config(const char *bname) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci return sharefs_appid_get(bname); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ciint __init sharefs_init_configfs(void) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci int err; 34062306a36Sopenharmony_ci struct configfs_subsystem *subsys; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci sharefs_info("init configfs"); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci sharefs_bid_entry_cachep = kmem_cache_create("sharefs_bid_entry_cachep", 34562306a36Sopenharmony_ci sizeof(struct sharefs_bid_entry), 0, 0, NULL); 34662306a36Sopenharmony_ci if (!sharefs_bid_entry_cachep) { 34762306a36Sopenharmony_ci sharefs_err("failed to create bid entry cachep"); 34862306a36Sopenharmony_ci err = -ENOMEM; 34962306a36Sopenharmony_ci goto out; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci subsys = &sharefs_subsystem; 35362306a36Sopenharmony_ci config_group_init(&subsys->su_group); 35462306a36Sopenharmony_ci mutex_init(&subsys->su_mutex); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci err = configfs_register_subsystem(subsys); 35762306a36Sopenharmony_ci if (err) 35862306a36Sopenharmony_ci sharefs_err("failed to register subsystem"); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ciout: 36162306a36Sopenharmony_ci return err; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_civoid sharefs_exit_configfs(void) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci sharefs_info("sharefs exit configfs"); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci configfs_unregister_subsystem(&sharefs_subsystem); 36962306a36Sopenharmony_ci clear_appid_hash_entry(); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci kmem_cache_destroy(sharefs_bid_entry_cachep); 37262306a36Sopenharmony_ci}