17bd1d409SAlexander Shishkin /* 27bd1d409SAlexander Shishkin * System Trace Module (STM) master/channel allocation policy management 37bd1d409SAlexander Shishkin * Copyright (c) 2014, Intel Corporation. 47bd1d409SAlexander Shishkin * 57bd1d409SAlexander Shishkin * This program is free software; you can redistribute it and/or modify it 67bd1d409SAlexander Shishkin * under the terms and conditions of the GNU General Public License, 77bd1d409SAlexander Shishkin * version 2, as published by the Free Software Foundation. 87bd1d409SAlexander Shishkin * 97bd1d409SAlexander Shishkin * This program is distributed in the hope it will be useful, but WITHOUT 107bd1d409SAlexander Shishkin * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 117bd1d409SAlexander Shishkin * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 127bd1d409SAlexander Shishkin * more details. 137bd1d409SAlexander Shishkin * 147bd1d409SAlexander Shishkin * A master/channel allocation policy allows mapping string identifiers to 157bd1d409SAlexander Shishkin * master and channel ranges, where allocation can be done. 167bd1d409SAlexander Shishkin */ 177bd1d409SAlexander Shishkin 187bd1d409SAlexander Shishkin #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 197bd1d409SAlexander Shishkin 207bd1d409SAlexander Shishkin #include <linux/types.h> 217bd1d409SAlexander Shishkin #include <linux/module.h> 227bd1d409SAlexander Shishkin #include <linux/device.h> 237bd1d409SAlexander Shishkin #include <linux/configfs.h> 247bd1d409SAlexander Shishkin #include <linux/slab.h> 257bd1d409SAlexander Shishkin #include <linux/stm.h> 267bd1d409SAlexander Shishkin #include "stm.h" 277bd1d409SAlexander Shishkin 287bd1d409SAlexander Shishkin /* 297bd1d409SAlexander Shishkin * STP Master/Channel allocation policy configfs layout. 307bd1d409SAlexander Shishkin */ 317bd1d409SAlexander Shishkin 327bd1d409SAlexander Shishkin struct stp_policy { 337bd1d409SAlexander Shishkin struct config_group group; 347bd1d409SAlexander Shishkin struct stm_device *stm; 357bd1d409SAlexander Shishkin }; 367bd1d409SAlexander Shishkin 377bd1d409SAlexander Shishkin struct stp_policy_node { 387bd1d409SAlexander Shishkin struct config_group group; 397bd1d409SAlexander Shishkin struct stp_policy *policy; 407bd1d409SAlexander Shishkin unsigned int first_master; 417bd1d409SAlexander Shishkin unsigned int last_master; 427bd1d409SAlexander Shishkin unsigned int first_channel; 437bd1d409SAlexander Shishkin unsigned int last_channel; 447bd1d409SAlexander Shishkin }; 457bd1d409SAlexander Shishkin 467bd1d409SAlexander Shishkin static struct configfs_subsystem stp_policy_subsys; 477bd1d409SAlexander Shishkin 487bd1d409SAlexander Shishkin void stp_policy_node_get_ranges(struct stp_policy_node *policy_node, 497bd1d409SAlexander Shishkin unsigned int *mstart, unsigned int *mend, 507bd1d409SAlexander Shishkin unsigned int *cstart, unsigned int *cend) 517bd1d409SAlexander Shishkin { 527bd1d409SAlexander Shishkin *mstart = policy_node->first_master; 537bd1d409SAlexander Shishkin *mend = policy_node->last_master; 547bd1d409SAlexander Shishkin *cstart = policy_node->first_channel; 557bd1d409SAlexander Shishkin *cend = policy_node->last_channel; 567bd1d409SAlexander Shishkin } 577bd1d409SAlexander Shishkin 587bd1d409SAlexander Shishkin static inline char *stp_policy_node_name(struct stp_policy_node *policy_node) 597bd1d409SAlexander Shishkin { 607bd1d409SAlexander Shishkin return policy_node->group.cg_item.ci_name ? : "<none>"; 617bd1d409SAlexander Shishkin } 627bd1d409SAlexander Shishkin 637bd1d409SAlexander Shishkin static inline struct stp_policy *to_stp_policy(struct config_item *item) 647bd1d409SAlexander Shishkin { 657bd1d409SAlexander Shishkin return item ? 667bd1d409SAlexander Shishkin container_of(to_config_group(item), struct stp_policy, group) : 677bd1d409SAlexander Shishkin NULL; 687bd1d409SAlexander Shishkin } 697bd1d409SAlexander Shishkin 707bd1d409SAlexander Shishkin static inline struct stp_policy_node * 717bd1d409SAlexander Shishkin to_stp_policy_node(struct config_item *item) 727bd1d409SAlexander Shishkin { 737bd1d409SAlexander Shishkin return item ? 747bd1d409SAlexander Shishkin container_of(to_config_group(item), struct stp_policy_node, 757bd1d409SAlexander Shishkin group) : 767bd1d409SAlexander Shishkin NULL; 777bd1d409SAlexander Shishkin } 787bd1d409SAlexander Shishkin 799aa3d651SLinus Torvalds static ssize_t 809aa3d651SLinus Torvalds stp_policy_node_masters_show(struct config_item *item, char *page) 817bd1d409SAlexander Shishkin { 829aa3d651SLinus Torvalds struct stp_policy_node *policy_node = to_stp_policy_node(item); 837bd1d409SAlexander Shishkin ssize_t count; 847bd1d409SAlexander Shishkin 857bd1d409SAlexander Shishkin count = sprintf(page, "%u %u\n", policy_node->first_master, 867bd1d409SAlexander Shishkin policy_node->last_master); 877bd1d409SAlexander Shishkin 887bd1d409SAlexander Shishkin return count; 897bd1d409SAlexander Shishkin } 907bd1d409SAlexander Shishkin 917bd1d409SAlexander Shishkin static ssize_t 929aa3d651SLinus Torvalds stp_policy_node_masters_store(struct config_item *item, const char *page, 939aa3d651SLinus Torvalds size_t count) 947bd1d409SAlexander Shishkin { 959aa3d651SLinus Torvalds struct stp_policy_node *policy_node = to_stp_policy_node(item); 967bd1d409SAlexander Shishkin unsigned int first, last; 977bd1d409SAlexander Shishkin struct stm_device *stm; 987bd1d409SAlexander Shishkin char *p = (char *)page; 997bd1d409SAlexander Shishkin ssize_t ret = -ENODEV; 1007bd1d409SAlexander Shishkin 1017bd1d409SAlexander Shishkin if (sscanf(p, "%u %u", &first, &last) != 2) 1027bd1d409SAlexander Shishkin return -EINVAL; 1037bd1d409SAlexander Shishkin 1047bd1d409SAlexander Shishkin mutex_lock(&stp_policy_subsys.su_mutex); 1057bd1d409SAlexander Shishkin stm = policy_node->policy->stm; 1067bd1d409SAlexander Shishkin if (!stm) 1077bd1d409SAlexander Shishkin goto unlock; 1087bd1d409SAlexander Shishkin 1097bd1d409SAlexander Shishkin /* must be within [sw_start..sw_end], which is an inclusive range */ 1107bd1d409SAlexander Shishkin if (first > INT_MAX || last > INT_MAX || first > last || 1117bd1d409SAlexander Shishkin first < stm->data->sw_start || 1127bd1d409SAlexander Shishkin last > stm->data->sw_end) { 1137bd1d409SAlexander Shishkin ret = -ERANGE; 1147bd1d409SAlexander Shishkin goto unlock; 1157bd1d409SAlexander Shishkin } 1167bd1d409SAlexander Shishkin 1177bd1d409SAlexander Shishkin ret = count; 1187bd1d409SAlexander Shishkin policy_node->first_master = first; 1197bd1d409SAlexander Shishkin policy_node->last_master = last; 1207bd1d409SAlexander Shishkin 1217bd1d409SAlexander Shishkin unlock: 1227bd1d409SAlexander Shishkin mutex_unlock(&stp_policy_subsys.su_mutex); 1237bd1d409SAlexander Shishkin 1247bd1d409SAlexander Shishkin return ret; 1257bd1d409SAlexander Shishkin } 1267bd1d409SAlexander Shishkin 1277bd1d409SAlexander Shishkin static ssize_t 1289aa3d651SLinus Torvalds stp_policy_node_channels_show(struct config_item *item, char *page) 1297bd1d409SAlexander Shishkin { 1309aa3d651SLinus Torvalds struct stp_policy_node *policy_node = to_stp_policy_node(item); 1317bd1d409SAlexander Shishkin ssize_t count; 1327bd1d409SAlexander Shishkin 1337bd1d409SAlexander Shishkin count = sprintf(page, "%u %u\n", policy_node->first_channel, 1347bd1d409SAlexander Shishkin policy_node->last_channel); 1357bd1d409SAlexander Shishkin 1367bd1d409SAlexander Shishkin return count; 1377bd1d409SAlexander Shishkin } 1387bd1d409SAlexander Shishkin 1397bd1d409SAlexander Shishkin static ssize_t 1409aa3d651SLinus Torvalds stp_policy_node_channels_store(struct config_item *item, const char *page, 1419aa3d651SLinus Torvalds size_t count) 1427bd1d409SAlexander Shishkin { 1439aa3d651SLinus Torvalds struct stp_policy_node *policy_node = to_stp_policy_node(item); 1447bd1d409SAlexander Shishkin unsigned int first, last; 1457bd1d409SAlexander Shishkin struct stm_device *stm; 1467bd1d409SAlexander Shishkin char *p = (char *)page; 1477bd1d409SAlexander Shishkin ssize_t ret = -ENODEV; 1487bd1d409SAlexander Shishkin 1497bd1d409SAlexander Shishkin if (sscanf(p, "%u %u", &first, &last) != 2) 1507bd1d409SAlexander Shishkin return -EINVAL; 1517bd1d409SAlexander Shishkin 1527bd1d409SAlexander Shishkin mutex_lock(&stp_policy_subsys.su_mutex); 1537bd1d409SAlexander Shishkin stm = policy_node->policy->stm; 1547bd1d409SAlexander Shishkin if (!stm) 1557bd1d409SAlexander Shishkin goto unlock; 1567bd1d409SAlexander Shishkin 1577bd1d409SAlexander Shishkin if (first > INT_MAX || last > INT_MAX || first > last || 1587bd1d409SAlexander Shishkin last >= stm->data->sw_nchannels) { 1597bd1d409SAlexander Shishkin ret = -ERANGE; 1607bd1d409SAlexander Shishkin goto unlock; 1617bd1d409SAlexander Shishkin } 1627bd1d409SAlexander Shishkin 1637bd1d409SAlexander Shishkin ret = count; 1647bd1d409SAlexander Shishkin policy_node->first_channel = first; 1657bd1d409SAlexander Shishkin policy_node->last_channel = last; 1667bd1d409SAlexander Shishkin 1677bd1d409SAlexander Shishkin unlock: 1687bd1d409SAlexander Shishkin mutex_unlock(&stp_policy_subsys.su_mutex); 1697bd1d409SAlexander Shishkin 1707bd1d409SAlexander Shishkin return ret; 1717bd1d409SAlexander Shishkin } 1727bd1d409SAlexander Shishkin 1737bd1d409SAlexander Shishkin static void stp_policy_node_release(struct config_item *item) 1747bd1d409SAlexander Shishkin { 1757bd1d409SAlexander Shishkin kfree(to_stp_policy_node(item)); 1767bd1d409SAlexander Shishkin } 1777bd1d409SAlexander Shishkin 1787bd1d409SAlexander Shishkin static struct configfs_item_operations stp_policy_node_item_ops = { 1797bd1d409SAlexander Shishkin .release = stp_policy_node_release, 1807bd1d409SAlexander Shishkin }; 1817bd1d409SAlexander Shishkin 1829aa3d651SLinus Torvalds CONFIGFS_ATTR(stp_policy_node_, masters); 1839aa3d651SLinus Torvalds CONFIGFS_ATTR(stp_policy_node_, channels); 1847bd1d409SAlexander Shishkin 1857bd1d409SAlexander Shishkin static struct configfs_attribute *stp_policy_node_attrs[] = { 1869aa3d651SLinus Torvalds &stp_policy_node_attr_masters, 1879aa3d651SLinus Torvalds &stp_policy_node_attr_channels, 1887bd1d409SAlexander Shishkin NULL, 1897bd1d409SAlexander Shishkin }; 1907bd1d409SAlexander Shishkin 1917bd1d409SAlexander Shishkin static struct config_item_type stp_policy_type; 1927bd1d409SAlexander Shishkin static struct config_item_type stp_policy_node_type; 1937bd1d409SAlexander Shishkin 1947bd1d409SAlexander Shishkin static struct config_group * 1957bd1d409SAlexander Shishkin stp_policy_node_make(struct config_group *group, const char *name) 1967bd1d409SAlexander Shishkin { 1977bd1d409SAlexander Shishkin struct stp_policy_node *policy_node, *parent_node; 1987bd1d409SAlexander Shishkin struct stp_policy *policy; 1997bd1d409SAlexander Shishkin 2007bd1d409SAlexander Shishkin if (group->cg_item.ci_type == &stp_policy_type) { 2017bd1d409SAlexander Shishkin policy = container_of(group, struct stp_policy, group); 2027bd1d409SAlexander Shishkin } else { 2037bd1d409SAlexander Shishkin parent_node = container_of(group, struct stp_policy_node, 2047bd1d409SAlexander Shishkin group); 2057bd1d409SAlexander Shishkin policy = parent_node->policy; 2067bd1d409SAlexander Shishkin } 2077bd1d409SAlexander Shishkin 2087bd1d409SAlexander Shishkin if (!policy->stm) 2097bd1d409SAlexander Shishkin return ERR_PTR(-ENODEV); 2107bd1d409SAlexander Shishkin 2117bd1d409SAlexander Shishkin policy_node = kzalloc(sizeof(struct stp_policy_node), GFP_KERNEL); 2127bd1d409SAlexander Shishkin if (!policy_node) 2137bd1d409SAlexander Shishkin return ERR_PTR(-ENOMEM); 2147bd1d409SAlexander Shishkin 2157bd1d409SAlexander Shishkin config_group_init_type_name(&policy_node->group, name, 2167bd1d409SAlexander Shishkin &stp_policy_node_type); 2177bd1d409SAlexander Shishkin 2187bd1d409SAlexander Shishkin policy_node->policy = policy; 2197bd1d409SAlexander Shishkin 2207bd1d409SAlexander Shishkin /* default values for the attributes */ 2217bd1d409SAlexander Shishkin policy_node->first_master = policy->stm->data->sw_start; 2227bd1d409SAlexander Shishkin policy_node->last_master = policy->stm->data->sw_end; 2237bd1d409SAlexander Shishkin policy_node->first_channel = 0; 2247bd1d409SAlexander Shishkin policy_node->last_channel = policy->stm->data->sw_nchannels - 1; 2257bd1d409SAlexander Shishkin 2267bd1d409SAlexander Shishkin return &policy_node->group; 2277bd1d409SAlexander Shishkin } 2287bd1d409SAlexander Shishkin 2297bd1d409SAlexander Shishkin static void 2307bd1d409SAlexander Shishkin stp_policy_node_drop(struct config_group *group, struct config_item *item) 2317bd1d409SAlexander Shishkin { 2327bd1d409SAlexander Shishkin config_item_put(item); 2337bd1d409SAlexander Shishkin } 2347bd1d409SAlexander Shishkin 2357bd1d409SAlexander Shishkin static struct configfs_group_operations stp_policy_node_group_ops = { 2367bd1d409SAlexander Shishkin .make_group = stp_policy_node_make, 2377bd1d409SAlexander Shishkin .drop_item = stp_policy_node_drop, 2387bd1d409SAlexander Shishkin }; 2397bd1d409SAlexander Shishkin 2407bd1d409SAlexander Shishkin static struct config_item_type stp_policy_node_type = { 2417bd1d409SAlexander Shishkin .ct_item_ops = &stp_policy_node_item_ops, 2427bd1d409SAlexander Shishkin .ct_group_ops = &stp_policy_node_group_ops, 2437bd1d409SAlexander Shishkin .ct_attrs = stp_policy_node_attrs, 2447bd1d409SAlexander Shishkin .ct_owner = THIS_MODULE, 2457bd1d409SAlexander Shishkin }; 2467bd1d409SAlexander Shishkin 2477bd1d409SAlexander Shishkin /* 2487bd1d409SAlexander Shishkin * Root group: policies. 2497bd1d409SAlexander Shishkin */ 2509aa3d651SLinus Torvalds static ssize_t stp_policy_device_show(struct config_item *item, 2517bd1d409SAlexander Shishkin char *page) 2527bd1d409SAlexander Shishkin { 2537bd1d409SAlexander Shishkin struct stp_policy *policy = to_stp_policy(item); 2547bd1d409SAlexander Shishkin ssize_t count; 2557bd1d409SAlexander Shishkin 2567bd1d409SAlexander Shishkin count = sprintf(page, "%s\n", 2577bd1d409SAlexander Shishkin (policy && policy->stm) ? 2587bd1d409SAlexander Shishkin policy->stm->data->name : 2597bd1d409SAlexander Shishkin "<none>"); 2607bd1d409SAlexander Shishkin 2617bd1d409SAlexander Shishkin return count; 2627bd1d409SAlexander Shishkin } 2637bd1d409SAlexander Shishkin 2649aa3d651SLinus Torvalds CONFIGFS_ATTR_RO(stp_policy_, device); 2659aa3d651SLinus Torvalds 2669aa3d651SLinus Torvalds static struct configfs_attribute *stp_policy_attrs[] = { 2679aa3d651SLinus Torvalds &stp_policy_attr_device, 2689aa3d651SLinus Torvalds NULL, 2699aa3d651SLinus Torvalds }; 2709aa3d651SLinus Torvalds 2717bd1d409SAlexander Shishkin void stp_policy_unbind(struct stp_policy *policy) 2727bd1d409SAlexander Shishkin { 2737bd1d409SAlexander Shishkin struct stm_device *stm = policy->stm; 2747bd1d409SAlexander Shishkin 2757bd1d409SAlexander Shishkin if (WARN_ON_ONCE(!policy->stm)) 2767bd1d409SAlexander Shishkin return; 2777bd1d409SAlexander Shishkin 2787bd1d409SAlexander Shishkin mutex_lock(&stm->policy_mutex); 2797bd1d409SAlexander Shishkin stm->policy = NULL; 2807bd1d409SAlexander Shishkin mutex_unlock(&stm->policy_mutex); 2817bd1d409SAlexander Shishkin 2827bd1d409SAlexander Shishkin policy->stm = NULL; 2837bd1d409SAlexander Shishkin 2847bd1d409SAlexander Shishkin stm_put_device(stm); 2857bd1d409SAlexander Shishkin } 2867bd1d409SAlexander Shishkin 2877bd1d409SAlexander Shishkin static void stp_policy_release(struct config_item *item) 2887bd1d409SAlexander Shishkin { 2897bd1d409SAlexander Shishkin struct stp_policy *policy = to_stp_policy(item); 2907bd1d409SAlexander Shishkin 2917bd1d409SAlexander Shishkin stp_policy_unbind(policy); 2927bd1d409SAlexander Shishkin kfree(policy); 2937bd1d409SAlexander Shishkin } 2947bd1d409SAlexander Shishkin 2957bd1d409SAlexander Shishkin static struct configfs_item_operations stp_policy_item_ops = { 2967bd1d409SAlexander Shishkin .release = stp_policy_release, 2977bd1d409SAlexander Shishkin }; 2987bd1d409SAlexander Shishkin 2997bd1d409SAlexander Shishkin static struct configfs_group_operations stp_policy_group_ops = { 3007bd1d409SAlexander Shishkin .make_group = stp_policy_node_make, 3017bd1d409SAlexander Shishkin }; 3027bd1d409SAlexander Shishkin 3037bd1d409SAlexander Shishkin static struct config_item_type stp_policy_type = { 3047bd1d409SAlexander Shishkin .ct_item_ops = &stp_policy_item_ops, 3057bd1d409SAlexander Shishkin .ct_group_ops = &stp_policy_group_ops, 3067bd1d409SAlexander Shishkin .ct_attrs = stp_policy_attrs, 3077bd1d409SAlexander Shishkin .ct_owner = THIS_MODULE, 3087bd1d409SAlexander Shishkin }; 3097bd1d409SAlexander Shishkin 3107bd1d409SAlexander Shishkin static struct config_group * 3117bd1d409SAlexander Shishkin stp_policies_make(struct config_group *group, const char *name) 3127bd1d409SAlexander Shishkin { 3137bd1d409SAlexander Shishkin struct config_group *ret; 3147bd1d409SAlexander Shishkin struct stm_device *stm; 3157bd1d409SAlexander Shishkin char *devname, *p; 3167bd1d409SAlexander Shishkin 3177bd1d409SAlexander Shishkin devname = kasprintf(GFP_KERNEL, "%s", name); 3187bd1d409SAlexander Shishkin if (!devname) 3197bd1d409SAlexander Shishkin return ERR_PTR(-ENOMEM); 3207bd1d409SAlexander Shishkin 3217bd1d409SAlexander Shishkin /* 3227bd1d409SAlexander Shishkin * node must look like <device_name>.<policy_name>, where 3237bd1d409SAlexander Shishkin * <device_name> is the name of an existing stm device and 3247bd1d409SAlexander Shishkin * <policy_name> is an arbitrary string 3257bd1d409SAlexander Shishkin */ 3267bd1d409SAlexander Shishkin p = strchr(devname, '.'); 3277bd1d409SAlexander Shishkin if (!p) { 3287bd1d409SAlexander Shishkin kfree(devname); 3297bd1d409SAlexander Shishkin return ERR_PTR(-EINVAL); 3307bd1d409SAlexander Shishkin } 3317bd1d409SAlexander Shishkin 3327bd1d409SAlexander Shishkin *p++ = '\0'; 3337bd1d409SAlexander Shishkin 3347bd1d409SAlexander Shishkin stm = stm_find_device(devname); 3357bd1d409SAlexander Shishkin kfree(devname); 3367bd1d409SAlexander Shishkin 3377bd1d409SAlexander Shishkin if (!stm) 3387bd1d409SAlexander Shishkin return ERR_PTR(-ENODEV); 3397bd1d409SAlexander Shishkin 3407bd1d409SAlexander Shishkin mutex_lock(&stm->policy_mutex); 3417bd1d409SAlexander Shishkin if (stm->policy) { 3427bd1d409SAlexander Shishkin ret = ERR_PTR(-EBUSY); 3437bd1d409SAlexander Shishkin goto unlock_policy; 3447bd1d409SAlexander Shishkin } 3457bd1d409SAlexander Shishkin 3467bd1d409SAlexander Shishkin stm->policy = kzalloc(sizeof(*stm->policy), GFP_KERNEL); 3477bd1d409SAlexander Shishkin if (!stm->policy) { 3487bd1d409SAlexander Shishkin ret = ERR_PTR(-ENOMEM); 3497bd1d409SAlexander Shishkin goto unlock_policy; 3507bd1d409SAlexander Shishkin } 3517bd1d409SAlexander Shishkin 3527bd1d409SAlexander Shishkin config_group_init_type_name(&stm->policy->group, name, 3537bd1d409SAlexander Shishkin &stp_policy_type); 3547bd1d409SAlexander Shishkin stm->policy->stm = stm; 3557bd1d409SAlexander Shishkin 3567bd1d409SAlexander Shishkin ret = &stm->policy->group; 3577bd1d409SAlexander Shishkin 3587bd1d409SAlexander Shishkin unlock_policy: 3597bd1d409SAlexander Shishkin mutex_unlock(&stm->policy_mutex); 3607bd1d409SAlexander Shishkin 3617bd1d409SAlexander Shishkin if (IS_ERR(ret)) 3627bd1d409SAlexander Shishkin stm_put_device(stm); 3637bd1d409SAlexander Shishkin 3647bd1d409SAlexander Shishkin return ret; 3657bd1d409SAlexander Shishkin } 3667bd1d409SAlexander Shishkin 3677bd1d409SAlexander Shishkin static struct configfs_group_operations stp_policies_group_ops = { 3687bd1d409SAlexander Shishkin .make_group = stp_policies_make, 3697bd1d409SAlexander Shishkin }; 3707bd1d409SAlexander Shishkin 3717bd1d409SAlexander Shishkin static struct config_item_type stp_policies_type = { 3727bd1d409SAlexander Shishkin .ct_group_ops = &stp_policies_group_ops, 3737bd1d409SAlexander Shishkin .ct_owner = THIS_MODULE, 3747bd1d409SAlexander Shishkin }; 3757bd1d409SAlexander Shishkin 3767bd1d409SAlexander Shishkin static struct configfs_subsystem stp_policy_subsys = { 3777bd1d409SAlexander Shishkin .su_group = { 3787bd1d409SAlexander Shishkin .cg_item = { 3797bd1d409SAlexander Shishkin .ci_namebuf = "stp-policy", 3807bd1d409SAlexander Shishkin .ci_type = &stp_policies_type, 3817bd1d409SAlexander Shishkin }, 3827bd1d409SAlexander Shishkin }, 3837bd1d409SAlexander Shishkin }; 3847bd1d409SAlexander Shishkin 3857bd1d409SAlexander Shishkin /* 3867bd1d409SAlexander Shishkin * Lock the policy mutex from the outside 3877bd1d409SAlexander Shishkin */ 3887bd1d409SAlexander Shishkin static struct stp_policy_node * 3897bd1d409SAlexander Shishkin __stp_policy_node_lookup(struct stp_policy *policy, char *s) 3907bd1d409SAlexander Shishkin { 3917bd1d409SAlexander Shishkin struct stp_policy_node *policy_node, *ret; 3927bd1d409SAlexander Shishkin struct list_head *head = &policy->group.cg_children; 3937bd1d409SAlexander Shishkin struct config_item *item; 3947bd1d409SAlexander Shishkin char *start, *end = s; 3957bd1d409SAlexander Shishkin 3967bd1d409SAlexander Shishkin if (list_empty(head)) 3977bd1d409SAlexander Shishkin return NULL; 3987bd1d409SAlexander Shishkin 3997bd1d409SAlexander Shishkin /* return the first entry if everything else fails */ 4007bd1d409SAlexander Shishkin item = list_entry(head->next, struct config_item, ci_entry); 4017bd1d409SAlexander Shishkin ret = to_stp_policy_node(item); 4027bd1d409SAlexander Shishkin 4037bd1d409SAlexander Shishkin next: 4047bd1d409SAlexander Shishkin for (;;) { 4057bd1d409SAlexander Shishkin start = strsep(&end, "/"); 4067bd1d409SAlexander Shishkin if (!start) 4077bd1d409SAlexander Shishkin break; 4087bd1d409SAlexander Shishkin 4097bd1d409SAlexander Shishkin if (!*start) 4107bd1d409SAlexander Shishkin continue; 4117bd1d409SAlexander Shishkin 4127bd1d409SAlexander Shishkin list_for_each_entry(item, head, ci_entry) { 4137bd1d409SAlexander Shishkin policy_node = to_stp_policy_node(item); 4147bd1d409SAlexander Shishkin 4157bd1d409SAlexander Shishkin if (!strcmp(start, 4167bd1d409SAlexander Shishkin policy_node->group.cg_item.ci_name)) { 4177bd1d409SAlexander Shishkin ret = policy_node; 4187bd1d409SAlexander Shishkin 4197bd1d409SAlexander Shishkin if (!end) 4207bd1d409SAlexander Shishkin goto out; 4217bd1d409SAlexander Shishkin 4227bd1d409SAlexander Shishkin head = &policy_node->group.cg_children; 4237bd1d409SAlexander Shishkin goto next; 4247bd1d409SAlexander Shishkin } 4257bd1d409SAlexander Shishkin } 4267bd1d409SAlexander Shishkin break; 4277bd1d409SAlexander Shishkin } 4287bd1d409SAlexander Shishkin 4297bd1d409SAlexander Shishkin out: 4307bd1d409SAlexander Shishkin return ret; 4317bd1d409SAlexander Shishkin } 4327bd1d409SAlexander Shishkin 4337bd1d409SAlexander Shishkin 4347bd1d409SAlexander Shishkin struct stp_policy_node * 4357bd1d409SAlexander Shishkin stp_policy_node_lookup(struct stm_device *stm, char *s) 4367bd1d409SAlexander Shishkin { 4377bd1d409SAlexander Shishkin struct stp_policy_node *policy_node = NULL; 4387bd1d409SAlexander Shishkin 4397bd1d409SAlexander Shishkin mutex_lock(&stp_policy_subsys.su_mutex); 4407bd1d409SAlexander Shishkin 4417bd1d409SAlexander Shishkin mutex_lock(&stm->policy_mutex); 4427bd1d409SAlexander Shishkin if (stm->policy) 4437bd1d409SAlexander Shishkin policy_node = __stp_policy_node_lookup(stm->policy, s); 4447bd1d409SAlexander Shishkin mutex_unlock(&stm->policy_mutex); 4457bd1d409SAlexander Shishkin 4467bd1d409SAlexander Shishkin if (policy_node) 4477bd1d409SAlexander Shishkin config_item_get(&policy_node->group.cg_item); 4487bd1d409SAlexander Shishkin mutex_unlock(&stp_policy_subsys.su_mutex); 4497bd1d409SAlexander Shishkin 4507bd1d409SAlexander Shishkin return policy_node; 4517bd1d409SAlexander Shishkin } 4527bd1d409SAlexander Shishkin 4537bd1d409SAlexander Shishkin void stp_policy_node_put(struct stp_policy_node *policy_node) 4547bd1d409SAlexander Shishkin { 4557bd1d409SAlexander Shishkin config_item_put(&policy_node->group.cg_item); 4567bd1d409SAlexander Shishkin } 4577bd1d409SAlexander Shishkin 4587bd1d409SAlexander Shishkin int __init stp_configfs_init(void) 4597bd1d409SAlexander Shishkin { 4607bd1d409SAlexander Shishkin int err; 4617bd1d409SAlexander Shishkin 4627bd1d409SAlexander Shishkin config_group_init(&stp_policy_subsys.su_group); 4637bd1d409SAlexander Shishkin mutex_init(&stp_policy_subsys.su_mutex); 4647bd1d409SAlexander Shishkin err = configfs_register_subsystem(&stp_policy_subsys); 4657bd1d409SAlexander Shishkin 4667bd1d409SAlexander Shishkin return err; 4677bd1d409SAlexander Shishkin } 4687bd1d409SAlexander Shishkin 4697bd1d409SAlexander Shishkin void __exit stp_configfs_exit(void) 4707bd1d409SAlexander Shishkin { 4717bd1d409SAlexander Shishkin configfs_unregister_subsystem(&stp_policy_subsys); 4727bd1d409SAlexander Shishkin } 473