18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * vim: noexpandtab ts=8 sts=0 sw=8: 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * configfs_example_macros.c - This file is a demonstration module 68c2ecf20Sopenharmony_ci * containing a number of configfs subsystems. It uses the helper 78c2ecf20Sopenharmony_ci * macros defined by configfs.h 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Based on sysfs: 108c2ecf20Sopenharmony_ci * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * configfs Copyright (C) 2005 Oracle. All rights reserved. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/configfs.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* 228c2ecf20Sopenharmony_ci * 01-childless 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * This first example is a childless subsystem. It cannot create 258c2ecf20Sopenharmony_ci * any config_items. It just has attributes. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * Note that we are enclosing the configfs_subsystem inside a container. 288c2ecf20Sopenharmony_ci * This is not necessary if a subsystem has no attributes directly 298c2ecf20Sopenharmony_ci * on the subsystem. See the next example, 02-simple-children, for 308c2ecf20Sopenharmony_ci * such a subsystem. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct childless { 348c2ecf20Sopenharmony_ci struct configfs_subsystem subsys; 358c2ecf20Sopenharmony_ci int showme; 368c2ecf20Sopenharmony_ci int storeme; 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic inline struct childless *to_childless(struct config_item *item) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci return container_of(to_configfs_subsystem(to_config_group(item)), 428c2ecf20Sopenharmony_ci struct childless, subsys); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic ssize_t childless_showme_show(struct config_item *item, char *page) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct childless *childless = to_childless(item); 488c2ecf20Sopenharmony_ci ssize_t pos; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci pos = sprintf(page, "%d\n", childless->showme); 518c2ecf20Sopenharmony_ci childless->showme++; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return pos; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic ssize_t childless_storeme_show(struct config_item *item, char *page) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci return sprintf(page, "%d\n", to_childless(item)->storeme); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic ssize_t childless_storeme_store(struct config_item *item, 628c2ecf20Sopenharmony_ci const char *page, size_t count) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct childless *childless = to_childless(item); 658c2ecf20Sopenharmony_ci int ret; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci ret = kstrtoint(page, 10, &childless->storeme); 688c2ecf20Sopenharmony_ci if (ret) 698c2ecf20Sopenharmony_ci return ret; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return count; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic ssize_t childless_description_show(struct config_item *item, char *page) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci return sprintf(page, 778c2ecf20Sopenharmony_ci"[01-childless]\n" 788c2ecf20Sopenharmony_ci"\n" 798c2ecf20Sopenharmony_ci"The childless subsystem is the simplest possible subsystem in\n" 808c2ecf20Sopenharmony_ci"configfs. It does not support the creation of child config_items.\n" 818c2ecf20Sopenharmony_ci"It only has a few attributes. In fact, it isn't much different\n" 828c2ecf20Sopenharmony_ci"than a directory in /proc.\n"); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ciCONFIGFS_ATTR_RO(childless_, showme); 868c2ecf20Sopenharmony_ciCONFIGFS_ATTR(childless_, storeme); 878c2ecf20Sopenharmony_ciCONFIGFS_ATTR_RO(childless_, description); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic struct configfs_attribute *childless_attrs[] = { 908c2ecf20Sopenharmony_ci &childless_attr_showme, 918c2ecf20Sopenharmony_ci &childless_attr_storeme, 928c2ecf20Sopenharmony_ci &childless_attr_description, 938c2ecf20Sopenharmony_ci NULL, 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic const struct config_item_type childless_type = { 978c2ecf20Sopenharmony_ci .ct_attrs = childless_attrs, 988c2ecf20Sopenharmony_ci .ct_owner = THIS_MODULE, 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic struct childless childless_subsys = { 1028c2ecf20Sopenharmony_ci .subsys = { 1038c2ecf20Sopenharmony_ci .su_group = { 1048c2ecf20Sopenharmony_ci .cg_item = { 1058c2ecf20Sopenharmony_ci .ci_namebuf = "01-childless", 1068c2ecf20Sopenharmony_ci .ci_type = &childless_type, 1078c2ecf20Sopenharmony_ci }, 1088c2ecf20Sopenharmony_ci }, 1098c2ecf20Sopenharmony_ci }, 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------- */ 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* 1158c2ecf20Sopenharmony_ci * 02-simple-children 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci * This example merely has a simple one-attribute child. Note that 1188c2ecf20Sopenharmony_ci * there is no extra attribute structure, as the child's attribute is 1198c2ecf20Sopenharmony_ci * known from the get-go. Also, there is no container for the 1208c2ecf20Sopenharmony_ci * subsystem, as it has no attributes of its own. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistruct simple_child { 1248c2ecf20Sopenharmony_ci struct config_item item; 1258c2ecf20Sopenharmony_ci int storeme; 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic inline struct simple_child *to_simple_child(struct config_item *item) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci return container_of(item, struct simple_child, item); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic ssize_t simple_child_storeme_show(struct config_item *item, char *page) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci return sprintf(page, "%d\n", to_simple_child(item)->storeme); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic ssize_t simple_child_storeme_store(struct config_item *item, 1398c2ecf20Sopenharmony_ci const char *page, size_t count) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct simple_child *simple_child = to_simple_child(item); 1428c2ecf20Sopenharmony_ci int ret; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci ret = kstrtoint(page, 10, &simple_child->storeme); 1458c2ecf20Sopenharmony_ci if (ret) 1468c2ecf20Sopenharmony_ci return ret; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return count; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ciCONFIGFS_ATTR(simple_child_, storeme); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic struct configfs_attribute *simple_child_attrs[] = { 1548c2ecf20Sopenharmony_ci &simple_child_attr_storeme, 1558c2ecf20Sopenharmony_ci NULL, 1568c2ecf20Sopenharmony_ci}; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void simple_child_release(struct config_item *item) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci kfree(to_simple_child(item)); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic struct configfs_item_operations simple_child_item_ops = { 1648c2ecf20Sopenharmony_ci .release = simple_child_release, 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic const struct config_item_type simple_child_type = { 1688c2ecf20Sopenharmony_ci .ct_item_ops = &simple_child_item_ops, 1698c2ecf20Sopenharmony_ci .ct_attrs = simple_child_attrs, 1708c2ecf20Sopenharmony_ci .ct_owner = THIS_MODULE, 1718c2ecf20Sopenharmony_ci}; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistruct simple_children { 1748c2ecf20Sopenharmony_ci struct config_group group; 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic inline struct simple_children *to_simple_children(struct config_item *item) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci return container_of(to_config_group(item), 1808c2ecf20Sopenharmony_ci struct simple_children, group); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic struct config_item *simple_children_make_item(struct config_group *group, 1848c2ecf20Sopenharmony_ci const char *name) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct simple_child *simple_child; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci simple_child = kzalloc(sizeof(struct simple_child), GFP_KERNEL); 1898c2ecf20Sopenharmony_ci if (!simple_child) 1908c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci config_item_init_type_name(&simple_child->item, name, 1938c2ecf20Sopenharmony_ci &simple_child_type); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return &simple_child->item; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic ssize_t simple_children_description_show(struct config_item *item, 1998c2ecf20Sopenharmony_ci char *page) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci return sprintf(page, 2028c2ecf20Sopenharmony_ci"[02-simple-children]\n" 2038c2ecf20Sopenharmony_ci"\n" 2048c2ecf20Sopenharmony_ci"This subsystem allows the creation of child config_items. These\n" 2058c2ecf20Sopenharmony_ci"items have only one attribute that is readable and writeable.\n"); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ciCONFIGFS_ATTR_RO(simple_children_, description); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic struct configfs_attribute *simple_children_attrs[] = { 2118c2ecf20Sopenharmony_ci &simple_children_attr_description, 2128c2ecf20Sopenharmony_ci NULL, 2138c2ecf20Sopenharmony_ci}; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic void simple_children_release(struct config_item *item) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci kfree(to_simple_children(item)); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic struct configfs_item_operations simple_children_item_ops = { 2218c2ecf20Sopenharmony_ci .release = simple_children_release, 2228c2ecf20Sopenharmony_ci}; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* 2258c2ecf20Sopenharmony_ci * Note that, since no extra work is required on ->drop_item(), 2268c2ecf20Sopenharmony_ci * no ->drop_item() is provided. 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_cistatic struct configfs_group_operations simple_children_group_ops = { 2298c2ecf20Sopenharmony_ci .make_item = simple_children_make_item, 2308c2ecf20Sopenharmony_ci}; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic const struct config_item_type simple_children_type = { 2338c2ecf20Sopenharmony_ci .ct_item_ops = &simple_children_item_ops, 2348c2ecf20Sopenharmony_ci .ct_group_ops = &simple_children_group_ops, 2358c2ecf20Sopenharmony_ci .ct_attrs = simple_children_attrs, 2368c2ecf20Sopenharmony_ci .ct_owner = THIS_MODULE, 2378c2ecf20Sopenharmony_ci}; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic struct configfs_subsystem simple_children_subsys = { 2408c2ecf20Sopenharmony_ci .su_group = { 2418c2ecf20Sopenharmony_ci .cg_item = { 2428c2ecf20Sopenharmony_ci .ci_namebuf = "02-simple-children", 2438c2ecf20Sopenharmony_ci .ci_type = &simple_children_type, 2448c2ecf20Sopenharmony_ci }, 2458c2ecf20Sopenharmony_ci }, 2468c2ecf20Sopenharmony_ci}; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------- */ 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/* 2518c2ecf20Sopenharmony_ci * 03-group-children 2528c2ecf20Sopenharmony_ci * 2538c2ecf20Sopenharmony_ci * This example reuses the simple_children group from above. However, 2548c2ecf20Sopenharmony_ci * the simple_children group is not the subsystem itself, it is a 2558c2ecf20Sopenharmony_ci * child of the subsystem. Creation of a group in the subsystem creates 2568c2ecf20Sopenharmony_ci * a new simple_children group. That group can then have simple_child 2578c2ecf20Sopenharmony_ci * children of its own. 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic struct config_group *group_children_make_group( 2618c2ecf20Sopenharmony_ci struct config_group *group, const char *name) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct simple_children *simple_children; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci simple_children = kzalloc(sizeof(struct simple_children), 2668c2ecf20Sopenharmony_ci GFP_KERNEL); 2678c2ecf20Sopenharmony_ci if (!simple_children) 2688c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci config_group_init_type_name(&simple_children->group, name, 2718c2ecf20Sopenharmony_ci &simple_children_type); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return &simple_children->group; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic ssize_t group_children_description_show(struct config_item *item, 2778c2ecf20Sopenharmony_ci char *page) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci return sprintf(page, 2808c2ecf20Sopenharmony_ci"[03-group-children]\n" 2818c2ecf20Sopenharmony_ci"\n" 2828c2ecf20Sopenharmony_ci"This subsystem allows the creation of child config_groups. These\n" 2838c2ecf20Sopenharmony_ci"groups are like the subsystem simple-children.\n"); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ciCONFIGFS_ATTR_RO(group_children_, description); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic struct configfs_attribute *group_children_attrs[] = { 2898c2ecf20Sopenharmony_ci &group_children_attr_description, 2908c2ecf20Sopenharmony_ci NULL, 2918c2ecf20Sopenharmony_ci}; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci/* 2948c2ecf20Sopenharmony_ci * Note that, since no extra work is required on ->drop_item(), 2958c2ecf20Sopenharmony_ci * no ->drop_item() is provided. 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_cistatic struct configfs_group_operations group_children_group_ops = { 2988c2ecf20Sopenharmony_ci .make_group = group_children_make_group, 2998c2ecf20Sopenharmony_ci}; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic const struct config_item_type group_children_type = { 3028c2ecf20Sopenharmony_ci .ct_group_ops = &group_children_group_ops, 3038c2ecf20Sopenharmony_ci .ct_attrs = group_children_attrs, 3048c2ecf20Sopenharmony_ci .ct_owner = THIS_MODULE, 3058c2ecf20Sopenharmony_ci}; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic struct configfs_subsystem group_children_subsys = { 3088c2ecf20Sopenharmony_ci .su_group = { 3098c2ecf20Sopenharmony_ci .cg_item = { 3108c2ecf20Sopenharmony_ci .ci_namebuf = "03-group-children", 3118c2ecf20Sopenharmony_ci .ci_type = &group_children_type, 3128c2ecf20Sopenharmony_ci }, 3138c2ecf20Sopenharmony_ci }, 3148c2ecf20Sopenharmony_ci}; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------- */ 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci/* 3198c2ecf20Sopenharmony_ci * We're now done with our subsystem definitions. 3208c2ecf20Sopenharmony_ci * For convenience in this module, here's a list of them all. It 3218c2ecf20Sopenharmony_ci * allows the init function to easily register them. Most modules 3228c2ecf20Sopenharmony_ci * will only have one subsystem, and will only call register_subsystem 3238c2ecf20Sopenharmony_ci * on it directly. 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_cistatic struct configfs_subsystem *example_subsys[] = { 3268c2ecf20Sopenharmony_ci &childless_subsys.subsys, 3278c2ecf20Sopenharmony_ci &simple_children_subsys, 3288c2ecf20Sopenharmony_ci &group_children_subsys, 3298c2ecf20Sopenharmony_ci NULL, 3308c2ecf20Sopenharmony_ci}; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int __init configfs_example_init(void) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct configfs_subsystem *subsys; 3358c2ecf20Sopenharmony_ci int ret, i; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci for (i = 0; example_subsys[i]; i++) { 3388c2ecf20Sopenharmony_ci subsys = example_subsys[i]; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci config_group_init(&subsys->su_group); 3418c2ecf20Sopenharmony_ci mutex_init(&subsys->su_mutex); 3428c2ecf20Sopenharmony_ci ret = configfs_register_subsystem(subsys); 3438c2ecf20Sopenharmony_ci if (ret) { 3448c2ecf20Sopenharmony_ci pr_err("Error %d while registering subsystem %s\n", 3458c2ecf20Sopenharmony_ci ret, subsys->su_group.cg_item.ci_namebuf); 3468c2ecf20Sopenharmony_ci goto out_unregister; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return 0; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ciout_unregister: 3538c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) 3548c2ecf20Sopenharmony_ci configfs_unregister_subsystem(example_subsys[i]); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return ret; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic void __exit configfs_example_exit(void) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci int i; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci for (i = 0; example_subsys[i]; i++) 3648c2ecf20Sopenharmony_ci configfs_unregister_subsystem(example_subsys[i]); 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cimodule_init(configfs_example_init); 3688c2ecf20Sopenharmony_cimodule_exit(configfs_example_exit); 3698c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 370