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 */ 110f57af6dfSChunyan Zhang if (first > last || first < stm->data->sw_start || 1117bd1d409SAlexander Shishkin last > stm->data->sw_end) { 1127bd1d409SAlexander Shishkin ret = -ERANGE; 1137bd1d409SAlexander Shishkin goto unlock; 1147bd1d409SAlexander Shishkin } 1157bd1d409SAlexander Shishkin 1167bd1d409SAlexander Shishkin ret = count; 1177bd1d409SAlexander Shishkin policy_node->first_master = first; 1187bd1d409SAlexander Shishkin policy_node->last_master = last; 1197bd1d409SAlexander Shishkin 1207bd1d409SAlexander Shishkin unlock: 1217bd1d409SAlexander Shishkin mutex_unlock(&stp_policy_subsys.su_mutex); 1227bd1d409SAlexander Shishkin 1237bd1d409SAlexander Shishkin return ret; 1247bd1d409SAlexander Shishkin } 1257bd1d409SAlexander Shishkin 1267bd1d409SAlexander Shishkin static ssize_t 1279aa3d651SLinus Torvalds stp_policy_node_channels_show(struct config_item *item, char *page) 1287bd1d409SAlexander Shishkin { 1299aa3d651SLinus Torvalds struct stp_policy_node *policy_node = to_stp_policy_node(item); 1307bd1d409SAlexander Shishkin ssize_t count; 1317bd1d409SAlexander Shishkin 1327bd1d409SAlexander Shishkin count = sprintf(page, "%u %u\n", policy_node->first_channel, 1337bd1d409SAlexander Shishkin policy_node->last_channel); 1347bd1d409SAlexander Shishkin 1357bd1d409SAlexander Shishkin return count; 1367bd1d409SAlexander Shishkin } 1377bd1d409SAlexander Shishkin 1387bd1d409SAlexander Shishkin static ssize_t 1399aa3d651SLinus Torvalds stp_policy_node_channels_store(struct config_item *item, const char *page, 1409aa3d651SLinus Torvalds size_t count) 1417bd1d409SAlexander Shishkin { 1429aa3d651SLinus Torvalds struct stp_policy_node *policy_node = to_stp_policy_node(item); 1437bd1d409SAlexander Shishkin unsigned int first, last; 1447bd1d409SAlexander Shishkin struct stm_device *stm; 1457bd1d409SAlexander Shishkin char *p = (char *)page; 1467bd1d409SAlexander Shishkin ssize_t ret = -ENODEV; 1477bd1d409SAlexander Shishkin 1487bd1d409SAlexander Shishkin if (sscanf(p, "%u %u", &first, &last) != 2) 1497bd1d409SAlexander Shishkin return -EINVAL; 1507bd1d409SAlexander Shishkin 1517bd1d409SAlexander Shishkin mutex_lock(&stp_policy_subsys.su_mutex); 1527bd1d409SAlexander Shishkin stm = policy_node->policy->stm; 1537bd1d409SAlexander Shishkin if (!stm) 1547bd1d409SAlexander Shishkin goto unlock; 1557bd1d409SAlexander Shishkin 1567bd1d409SAlexander Shishkin if (first > INT_MAX || last > INT_MAX || first > last || 1577bd1d409SAlexander Shishkin last >= stm->data->sw_nchannels) { 1587bd1d409SAlexander Shishkin ret = -ERANGE; 1597bd1d409SAlexander Shishkin goto unlock; 1607bd1d409SAlexander Shishkin } 1617bd1d409SAlexander Shishkin 1627bd1d409SAlexander Shishkin ret = count; 1637bd1d409SAlexander Shishkin policy_node->first_channel = first; 1647bd1d409SAlexander Shishkin policy_node->last_channel = last; 1657bd1d409SAlexander Shishkin 1667bd1d409SAlexander Shishkin unlock: 1677bd1d409SAlexander Shishkin mutex_unlock(&stp_policy_subsys.su_mutex); 1687bd1d409SAlexander Shishkin 1697bd1d409SAlexander Shishkin return ret; 1707bd1d409SAlexander Shishkin } 1717bd1d409SAlexander Shishkin 1727bd1d409SAlexander Shishkin static void stp_policy_node_release(struct config_item *item) 1737bd1d409SAlexander Shishkin { 1747bd1d409SAlexander Shishkin kfree(to_stp_policy_node(item)); 1757bd1d409SAlexander Shishkin } 1767bd1d409SAlexander Shishkin 1777bd1d409SAlexander Shishkin static struct configfs_item_operations stp_policy_node_item_ops = { 1787bd1d409SAlexander Shishkin .release = stp_policy_node_release, 1797bd1d409SAlexander Shishkin }; 1807bd1d409SAlexander Shishkin 1819aa3d651SLinus Torvalds CONFIGFS_ATTR(stp_policy_node_, masters); 1829aa3d651SLinus Torvalds CONFIGFS_ATTR(stp_policy_node_, channels); 1837bd1d409SAlexander Shishkin 1847bd1d409SAlexander Shishkin static struct configfs_attribute *stp_policy_node_attrs[] = { 1859aa3d651SLinus Torvalds &stp_policy_node_attr_masters, 1869aa3d651SLinus Torvalds &stp_policy_node_attr_channels, 1877bd1d409SAlexander Shishkin NULL, 1887bd1d409SAlexander Shishkin }; 1897bd1d409SAlexander Shishkin 1907bd1d409SAlexander Shishkin static struct config_item_type stp_policy_type; 1917bd1d409SAlexander Shishkin static struct config_item_type stp_policy_node_type; 1927bd1d409SAlexander Shishkin 1937bd1d409SAlexander Shishkin static struct config_group * 1947bd1d409SAlexander Shishkin stp_policy_node_make(struct config_group *group, const char *name) 1957bd1d409SAlexander Shishkin { 1967bd1d409SAlexander Shishkin struct stp_policy_node *policy_node, *parent_node; 1977bd1d409SAlexander Shishkin struct stp_policy *policy; 1987bd1d409SAlexander Shishkin 1997bd1d409SAlexander Shishkin if (group->cg_item.ci_type == &stp_policy_type) { 2007bd1d409SAlexander Shishkin policy = container_of(group, struct stp_policy, group); 2017bd1d409SAlexander Shishkin } else { 2027bd1d409SAlexander Shishkin parent_node = container_of(group, struct stp_policy_node, 2037bd1d409SAlexander Shishkin group); 2047bd1d409SAlexander Shishkin policy = parent_node->policy; 2057bd1d409SAlexander Shishkin } 2067bd1d409SAlexander Shishkin 2077bd1d409SAlexander Shishkin if (!policy->stm) 2087bd1d409SAlexander Shishkin return ERR_PTR(-ENODEV); 2097bd1d409SAlexander Shishkin 2107bd1d409SAlexander Shishkin policy_node = kzalloc(sizeof(struct stp_policy_node), GFP_KERNEL); 2117bd1d409SAlexander Shishkin if (!policy_node) 2127bd1d409SAlexander Shishkin return ERR_PTR(-ENOMEM); 2137bd1d409SAlexander Shishkin 2147bd1d409SAlexander Shishkin config_group_init_type_name(&policy_node->group, name, 2157bd1d409SAlexander Shishkin &stp_policy_node_type); 2167bd1d409SAlexander Shishkin 2177bd1d409SAlexander Shishkin policy_node->policy = policy; 2187bd1d409SAlexander Shishkin 2197bd1d409SAlexander Shishkin /* default values for the attributes */ 2207bd1d409SAlexander Shishkin policy_node->first_master = policy->stm->data->sw_start; 2217bd1d409SAlexander Shishkin policy_node->last_master = policy->stm->data->sw_end; 2227bd1d409SAlexander Shishkin policy_node->first_channel = 0; 2237bd1d409SAlexander Shishkin policy_node->last_channel = policy->stm->data->sw_nchannels - 1; 2247bd1d409SAlexander Shishkin 2257bd1d409SAlexander Shishkin return &policy_node->group; 2267bd1d409SAlexander Shishkin } 2277bd1d409SAlexander Shishkin 2287bd1d409SAlexander Shishkin static void 2297bd1d409SAlexander Shishkin stp_policy_node_drop(struct config_group *group, struct config_item *item) 2307bd1d409SAlexander Shishkin { 2317bd1d409SAlexander Shishkin config_item_put(item); 2327bd1d409SAlexander Shishkin } 2337bd1d409SAlexander Shishkin 2347bd1d409SAlexander Shishkin static struct configfs_group_operations stp_policy_node_group_ops = { 2357bd1d409SAlexander Shishkin .make_group = stp_policy_node_make, 2367bd1d409SAlexander Shishkin .drop_item = stp_policy_node_drop, 2377bd1d409SAlexander Shishkin }; 2387bd1d409SAlexander Shishkin 2397bd1d409SAlexander Shishkin static struct config_item_type stp_policy_node_type = { 2407bd1d409SAlexander Shishkin .ct_item_ops = &stp_policy_node_item_ops, 2417bd1d409SAlexander Shishkin .ct_group_ops = &stp_policy_node_group_ops, 2427bd1d409SAlexander Shishkin .ct_attrs = stp_policy_node_attrs, 2437bd1d409SAlexander Shishkin .ct_owner = THIS_MODULE, 2447bd1d409SAlexander Shishkin }; 2457bd1d409SAlexander Shishkin 2467bd1d409SAlexander Shishkin /* 2477bd1d409SAlexander Shishkin * Root group: policies. 2487bd1d409SAlexander Shishkin */ 2499aa3d651SLinus Torvalds static ssize_t stp_policy_device_show(struct config_item *item, 2507bd1d409SAlexander Shishkin char *page) 2517bd1d409SAlexander Shishkin { 2527bd1d409SAlexander Shishkin struct stp_policy *policy = to_stp_policy(item); 2537bd1d409SAlexander Shishkin ssize_t count; 2547bd1d409SAlexander Shishkin 2557bd1d409SAlexander Shishkin count = sprintf(page, "%s\n", 2567bd1d409SAlexander Shishkin (policy && policy->stm) ? 2577bd1d409SAlexander Shishkin policy->stm->data->name : 2587bd1d409SAlexander Shishkin "<none>"); 2597bd1d409SAlexander Shishkin 2607bd1d409SAlexander Shishkin return count; 2617bd1d409SAlexander Shishkin } 2627bd1d409SAlexander Shishkin 2639aa3d651SLinus Torvalds CONFIGFS_ATTR_RO(stp_policy_, device); 2649aa3d651SLinus Torvalds 2659aa3d651SLinus Torvalds static struct configfs_attribute *stp_policy_attrs[] = { 2669aa3d651SLinus Torvalds &stp_policy_attr_device, 2679aa3d651SLinus Torvalds NULL, 2689aa3d651SLinus Torvalds }; 2699aa3d651SLinus Torvalds 2707bd1d409SAlexander Shishkin void stp_policy_unbind(struct stp_policy *policy) 2717bd1d409SAlexander Shishkin { 2727bd1d409SAlexander Shishkin struct stm_device *stm = policy->stm; 2737bd1d409SAlexander Shishkin 2744c127fd1SAlexander Shishkin /* 2754c127fd1SAlexander Shishkin * stp_policy_release() will not call here if the policy is already 2764c127fd1SAlexander Shishkin * unbound; other users should not either, as no link exists between 2774c127fd1SAlexander Shishkin * this policy and anything else in that case 2784c127fd1SAlexander Shishkin */ 2797bd1d409SAlexander Shishkin if (WARN_ON_ONCE(!policy->stm)) 2807bd1d409SAlexander Shishkin return; 2817bd1d409SAlexander Shishkin 2824c127fd1SAlexander Shishkin lockdep_assert_held(&stm->policy_mutex); 2837bd1d409SAlexander Shishkin 2844c127fd1SAlexander Shishkin stm->policy = NULL; 2857bd1d409SAlexander Shishkin policy->stm = NULL; 2867bd1d409SAlexander Shishkin 2877bd1d409SAlexander Shishkin stm_put_device(stm); 2887bd1d409SAlexander Shishkin } 2897bd1d409SAlexander Shishkin 2907bd1d409SAlexander Shishkin static void stp_policy_release(struct config_item *item) 2917bd1d409SAlexander Shishkin { 2927bd1d409SAlexander Shishkin struct stp_policy *policy = to_stp_policy(item); 2934c127fd1SAlexander Shishkin struct stm_device *stm = policy->stm; 2947bd1d409SAlexander Shishkin 2954c127fd1SAlexander Shishkin /* a policy *can* be unbound and still exist in configfs tree */ 2964c127fd1SAlexander Shishkin if (!stm) 2974c127fd1SAlexander Shishkin return; 2984c127fd1SAlexander Shishkin 2994c127fd1SAlexander Shishkin mutex_lock(&stm->policy_mutex); 3007bd1d409SAlexander Shishkin stp_policy_unbind(policy); 3014c127fd1SAlexander Shishkin mutex_unlock(&stm->policy_mutex); 3024c127fd1SAlexander Shishkin 3037bd1d409SAlexander Shishkin kfree(policy); 3047bd1d409SAlexander Shishkin } 3057bd1d409SAlexander Shishkin 3067bd1d409SAlexander Shishkin static struct configfs_item_operations stp_policy_item_ops = { 3077bd1d409SAlexander Shishkin .release = stp_policy_release, 3087bd1d409SAlexander Shishkin }; 3097bd1d409SAlexander Shishkin 3107bd1d409SAlexander Shishkin static struct configfs_group_operations stp_policy_group_ops = { 3117bd1d409SAlexander Shishkin .make_group = stp_policy_node_make, 3127bd1d409SAlexander Shishkin }; 3137bd1d409SAlexander Shishkin 3147bd1d409SAlexander Shishkin static struct config_item_type stp_policy_type = { 3157bd1d409SAlexander Shishkin .ct_item_ops = &stp_policy_item_ops, 3167bd1d409SAlexander Shishkin .ct_group_ops = &stp_policy_group_ops, 3177bd1d409SAlexander Shishkin .ct_attrs = stp_policy_attrs, 3187bd1d409SAlexander Shishkin .ct_owner = THIS_MODULE, 3197bd1d409SAlexander Shishkin }; 3207bd1d409SAlexander Shishkin 3217bd1d409SAlexander Shishkin static struct config_group * 3227bd1d409SAlexander Shishkin stp_policies_make(struct config_group *group, const char *name) 3237bd1d409SAlexander Shishkin { 3247bd1d409SAlexander Shishkin struct config_group *ret; 3257bd1d409SAlexander Shishkin struct stm_device *stm; 3267bd1d409SAlexander Shishkin char *devname, *p; 3277bd1d409SAlexander Shishkin 3287bd1d409SAlexander Shishkin devname = kasprintf(GFP_KERNEL, "%s", name); 3297bd1d409SAlexander Shishkin if (!devname) 3307bd1d409SAlexander Shishkin return ERR_PTR(-ENOMEM); 3317bd1d409SAlexander Shishkin 3327bd1d409SAlexander Shishkin /* 3337bd1d409SAlexander Shishkin * node must look like <device_name>.<policy_name>, where 33459be422eSAlexander Shishkin * <device_name> is the name of an existing stm device; may 33559be422eSAlexander Shishkin * contain dots; 33659be422eSAlexander Shishkin * <policy_name> is an arbitrary string; may not contain dots 3377bd1d409SAlexander Shishkin */ 33859be422eSAlexander Shishkin p = strrchr(devname, '.'); 3397bd1d409SAlexander Shishkin if (!p) { 3407bd1d409SAlexander Shishkin kfree(devname); 3417bd1d409SAlexander Shishkin return ERR_PTR(-EINVAL); 3427bd1d409SAlexander Shishkin } 3437bd1d409SAlexander Shishkin 3447bd1d409SAlexander Shishkin *p++ = '\0'; 3457bd1d409SAlexander Shishkin 3467bd1d409SAlexander Shishkin stm = stm_find_device(devname); 3477bd1d409SAlexander Shishkin kfree(devname); 3487bd1d409SAlexander Shishkin 3497bd1d409SAlexander Shishkin if (!stm) 3507bd1d409SAlexander Shishkin return ERR_PTR(-ENODEV); 3517bd1d409SAlexander Shishkin 3527bd1d409SAlexander Shishkin mutex_lock(&stm->policy_mutex); 3537bd1d409SAlexander Shishkin if (stm->policy) { 3547bd1d409SAlexander Shishkin ret = ERR_PTR(-EBUSY); 3557bd1d409SAlexander Shishkin goto unlock_policy; 3567bd1d409SAlexander Shishkin } 3577bd1d409SAlexander Shishkin 3587bd1d409SAlexander Shishkin stm->policy = kzalloc(sizeof(*stm->policy), GFP_KERNEL); 3597bd1d409SAlexander Shishkin if (!stm->policy) { 3607bd1d409SAlexander Shishkin ret = ERR_PTR(-ENOMEM); 3617bd1d409SAlexander Shishkin goto unlock_policy; 3627bd1d409SAlexander Shishkin } 3637bd1d409SAlexander Shishkin 3647bd1d409SAlexander Shishkin config_group_init_type_name(&stm->policy->group, name, 3657bd1d409SAlexander Shishkin &stp_policy_type); 3667bd1d409SAlexander Shishkin stm->policy->stm = stm; 3677bd1d409SAlexander Shishkin 3687bd1d409SAlexander Shishkin ret = &stm->policy->group; 3697bd1d409SAlexander Shishkin 3707bd1d409SAlexander Shishkin unlock_policy: 3717bd1d409SAlexander Shishkin mutex_unlock(&stm->policy_mutex); 3727bd1d409SAlexander Shishkin 3737bd1d409SAlexander Shishkin if (IS_ERR(ret)) 3747bd1d409SAlexander Shishkin stm_put_device(stm); 3757bd1d409SAlexander Shishkin 3767bd1d409SAlexander Shishkin return ret; 3777bd1d409SAlexander Shishkin } 3787bd1d409SAlexander Shishkin 3797bd1d409SAlexander Shishkin static struct configfs_group_operations stp_policies_group_ops = { 3807bd1d409SAlexander Shishkin .make_group = stp_policies_make, 3817bd1d409SAlexander Shishkin }; 3827bd1d409SAlexander Shishkin 3837bd1d409SAlexander Shishkin static struct config_item_type stp_policies_type = { 3847bd1d409SAlexander Shishkin .ct_group_ops = &stp_policies_group_ops, 3857bd1d409SAlexander Shishkin .ct_owner = THIS_MODULE, 3867bd1d409SAlexander Shishkin }; 3877bd1d409SAlexander Shishkin 3887bd1d409SAlexander Shishkin static struct configfs_subsystem stp_policy_subsys = { 3897bd1d409SAlexander Shishkin .su_group = { 3907bd1d409SAlexander Shishkin .cg_item = { 3917bd1d409SAlexander Shishkin .ci_namebuf = "stp-policy", 3927bd1d409SAlexander Shishkin .ci_type = &stp_policies_type, 3937bd1d409SAlexander Shishkin }, 3947bd1d409SAlexander Shishkin }, 3957bd1d409SAlexander Shishkin }; 3967bd1d409SAlexander Shishkin 3977bd1d409SAlexander Shishkin /* 3987bd1d409SAlexander Shishkin * Lock the policy mutex from the outside 3997bd1d409SAlexander Shishkin */ 4007bd1d409SAlexander Shishkin static struct stp_policy_node * 4017bd1d409SAlexander Shishkin __stp_policy_node_lookup(struct stp_policy *policy, char *s) 4027bd1d409SAlexander Shishkin { 4037bd1d409SAlexander Shishkin struct stp_policy_node *policy_node, *ret; 4047bd1d409SAlexander Shishkin struct list_head *head = &policy->group.cg_children; 4057bd1d409SAlexander Shishkin struct config_item *item; 4067bd1d409SAlexander Shishkin char *start, *end = s; 4077bd1d409SAlexander Shishkin 4087bd1d409SAlexander Shishkin if (list_empty(head)) 4097bd1d409SAlexander Shishkin return NULL; 4107bd1d409SAlexander Shishkin 4117bd1d409SAlexander Shishkin /* return the first entry if everything else fails */ 4127bd1d409SAlexander Shishkin item = list_entry(head->next, struct config_item, ci_entry); 4137bd1d409SAlexander Shishkin ret = to_stp_policy_node(item); 4147bd1d409SAlexander Shishkin 4157bd1d409SAlexander Shishkin next: 4167bd1d409SAlexander Shishkin for (;;) { 4177bd1d409SAlexander Shishkin start = strsep(&end, "/"); 4187bd1d409SAlexander Shishkin if (!start) 4197bd1d409SAlexander Shishkin break; 4207bd1d409SAlexander Shishkin 4217bd1d409SAlexander Shishkin if (!*start) 4227bd1d409SAlexander Shishkin continue; 4237bd1d409SAlexander Shishkin 4247bd1d409SAlexander Shishkin list_for_each_entry(item, head, ci_entry) { 4257bd1d409SAlexander Shishkin policy_node = to_stp_policy_node(item); 4267bd1d409SAlexander Shishkin 4277bd1d409SAlexander Shishkin if (!strcmp(start, 4287bd1d409SAlexander Shishkin policy_node->group.cg_item.ci_name)) { 4297bd1d409SAlexander Shishkin ret = policy_node; 4307bd1d409SAlexander Shishkin 4317bd1d409SAlexander Shishkin if (!end) 4327bd1d409SAlexander Shishkin goto out; 4337bd1d409SAlexander Shishkin 4347bd1d409SAlexander Shishkin head = &policy_node->group.cg_children; 4357bd1d409SAlexander Shishkin goto next; 4367bd1d409SAlexander Shishkin } 4377bd1d409SAlexander Shishkin } 4387bd1d409SAlexander Shishkin break; 4397bd1d409SAlexander Shishkin } 4407bd1d409SAlexander Shishkin 4417bd1d409SAlexander Shishkin out: 4427bd1d409SAlexander Shishkin return ret; 4437bd1d409SAlexander Shishkin } 4447bd1d409SAlexander Shishkin 4457bd1d409SAlexander Shishkin 4467bd1d409SAlexander Shishkin struct stp_policy_node * 4477bd1d409SAlexander Shishkin stp_policy_node_lookup(struct stm_device *stm, char *s) 4487bd1d409SAlexander Shishkin { 4497bd1d409SAlexander Shishkin struct stp_policy_node *policy_node = NULL; 4507bd1d409SAlexander Shishkin 4517bd1d409SAlexander Shishkin mutex_lock(&stp_policy_subsys.su_mutex); 4527bd1d409SAlexander Shishkin 4537bd1d409SAlexander Shishkin mutex_lock(&stm->policy_mutex); 4547bd1d409SAlexander Shishkin if (stm->policy) 4557bd1d409SAlexander Shishkin policy_node = __stp_policy_node_lookup(stm->policy, s); 4567bd1d409SAlexander Shishkin mutex_unlock(&stm->policy_mutex); 4577bd1d409SAlexander Shishkin 4587bd1d409SAlexander Shishkin if (policy_node) 4597bd1d409SAlexander Shishkin config_item_get(&policy_node->group.cg_item); 4607bd1d409SAlexander Shishkin mutex_unlock(&stp_policy_subsys.su_mutex); 4617bd1d409SAlexander Shishkin 4627bd1d409SAlexander Shishkin return policy_node; 4637bd1d409SAlexander Shishkin } 4647bd1d409SAlexander Shishkin 4657bd1d409SAlexander Shishkin void stp_policy_node_put(struct stp_policy_node *policy_node) 4667bd1d409SAlexander Shishkin { 4677bd1d409SAlexander Shishkin config_item_put(&policy_node->group.cg_item); 4687bd1d409SAlexander Shishkin } 4697bd1d409SAlexander Shishkin 4707bd1d409SAlexander Shishkin int __init stp_configfs_init(void) 4717bd1d409SAlexander Shishkin { 4727bd1d409SAlexander Shishkin int err; 4737bd1d409SAlexander Shishkin 4747bd1d409SAlexander Shishkin config_group_init(&stp_policy_subsys.su_group); 4757bd1d409SAlexander Shishkin mutex_init(&stp_policy_subsys.su_mutex); 4767bd1d409SAlexander Shishkin err = configfs_register_subsystem(&stp_policy_subsys); 4777bd1d409SAlexander Shishkin 4787bd1d409SAlexander Shishkin return err; 4797bd1d409SAlexander Shishkin } 4807bd1d409SAlexander Shishkin 4817bd1d409SAlexander Shishkin void __exit stp_configfs_exit(void) 4827bd1d409SAlexander Shishkin { 4837bd1d409SAlexander Shishkin configfs_unregister_subsystem(&stp_policy_subsys); 4847bd1d409SAlexander Shishkin } 485