linux/drivers/hwtracing/stm/policy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * System Trace Module (STM) master/channel allocation policy management
   4 * Copyright (c) 2014, Intel Corporation.
   5 *
   6 * A master/channel allocation policy allows mapping string identifiers to
   7 * master and channel ranges, where allocation can be done.
   8 */
   9
  10#define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
  11
  12#include <linux/types.h>
  13#include <linux/module.h>
  14#include <linux/device.h>
  15#include <linux/configfs.h>
  16#include <linux/slab.h>
  17#include <linux/stm.h>
  18#include "stm.h"
  19
  20/*
  21 * STP Master/Channel allocation policy configfs layout.
  22 */
  23
  24struct stp_policy {
  25        struct config_group     group;
  26        struct stm_device       *stm;
  27};
  28
  29struct stp_policy_node {
  30        struct config_group     group;
  31        struct stp_policy       *policy;
  32        unsigned int            first_master;
  33        unsigned int            last_master;
  34        unsigned int            first_channel;
  35        unsigned int            last_channel;
  36        /* this is the one that's exposed to the attributes */
  37        unsigned char           priv[0];
  38};
  39
  40void *stp_policy_node_priv(struct stp_policy_node *pn)
  41{
  42        if (!pn)
  43                return NULL;
  44
  45        return pn->priv;
  46}
  47
  48static struct configfs_subsystem stp_policy_subsys;
  49
  50void stp_policy_node_get_ranges(struct stp_policy_node *policy_node,
  51                                unsigned int *mstart, unsigned int *mend,
  52                                unsigned int *cstart, unsigned int *cend)
  53{
  54        *mstart = policy_node->first_master;
  55        *mend   = policy_node->last_master;
  56        *cstart = policy_node->first_channel;
  57        *cend   = policy_node->last_channel;
  58}
  59
  60static inline char *stp_policy_node_name(struct stp_policy_node *policy_node)
  61{
  62        return policy_node->group.cg_item.ci_name ? : "<none>";
  63}
  64
  65static inline struct stp_policy *to_stp_policy(struct config_item *item)
  66{
  67        return item ?
  68                container_of(to_config_group(item), struct stp_policy, group) :
  69                NULL;
  70}
  71
  72static inline struct stp_policy_node *
  73to_stp_policy_node(struct config_item *item)
  74{
  75        return item ?
  76                container_of(to_config_group(item), struct stp_policy_node,
  77                             group) :
  78                NULL;
  79}
  80
  81void *to_pdrv_policy_node(struct config_item *item)
  82{
  83        struct stp_policy_node *node = to_stp_policy_node(item);
  84
  85        return stp_policy_node_priv(node);
  86}
  87EXPORT_SYMBOL_GPL(to_pdrv_policy_node);
  88
  89static ssize_t
  90stp_policy_node_masters_show(struct config_item *item, char *page)
  91{
  92        struct stp_policy_node *policy_node = to_stp_policy_node(item);
  93        ssize_t count;
  94
  95        count = sprintf(page, "%u %u\n", policy_node->first_master,
  96                        policy_node->last_master);
  97
  98        return count;
  99}
 100
 101static ssize_t
 102stp_policy_node_masters_store(struct config_item *item, const char *page,
 103                              size_t count)
 104{
 105        struct stp_policy_node *policy_node = to_stp_policy_node(item);
 106        unsigned int first, last;
 107        struct stm_device *stm;
 108        char *p = (char *)page;
 109        ssize_t ret = -ENODEV;
 110
 111        if (sscanf(p, "%u %u", &first, &last) != 2)
 112                return -EINVAL;
 113
 114        mutex_lock(&stp_policy_subsys.su_mutex);
 115        stm = policy_node->policy->stm;
 116        if (!stm)
 117                goto unlock;
 118
 119        /* must be within [sw_start..sw_end], which is an inclusive range */
 120        if (first > last || first < stm->data->sw_start ||
 121            last > stm->data->sw_end) {
 122                ret = -ERANGE;
 123                goto unlock;
 124        }
 125
 126        ret = count;
 127        policy_node->first_master = first;
 128        policy_node->last_master = last;
 129
 130unlock:
 131        mutex_unlock(&stp_policy_subsys.su_mutex);
 132
 133        return ret;
 134}
 135
 136static ssize_t
 137stp_policy_node_channels_show(struct config_item *item, char *page)
 138{
 139        struct stp_policy_node *policy_node = to_stp_policy_node(item);
 140        ssize_t count;
 141
 142        count = sprintf(page, "%u %u\n", policy_node->first_channel,
 143                        policy_node->last_channel);
 144
 145        return count;
 146}
 147
 148static ssize_t
 149stp_policy_node_channels_store(struct config_item *item, const char *page,
 150                               size_t count)
 151{
 152        struct stp_policy_node *policy_node = to_stp_policy_node(item);
 153        unsigned int first, last;
 154        struct stm_device *stm;
 155        char *p = (char *)page;
 156        ssize_t ret = -ENODEV;
 157
 158        if (sscanf(p, "%u %u", &first, &last) != 2)
 159                return -EINVAL;
 160
 161        mutex_lock(&stp_policy_subsys.su_mutex);
 162        stm = policy_node->policy->stm;
 163        if (!stm)
 164                goto unlock;
 165
 166        if (first > INT_MAX || last > INT_MAX || first > last ||
 167            last >= stm->data->sw_nchannels) {
 168                ret = -ERANGE;
 169                goto unlock;
 170        }
 171
 172        ret = count;
 173        policy_node->first_channel = first;
 174        policy_node->last_channel = last;
 175
 176unlock:
 177        mutex_unlock(&stp_policy_subsys.su_mutex);
 178
 179        return ret;
 180}
 181
 182static void stp_policy_node_release(struct config_item *item)
 183{
 184        struct stp_policy_node *node = to_stp_policy_node(item);
 185
 186        kfree(node);
 187}
 188
 189static struct configfs_item_operations stp_policy_node_item_ops = {
 190        .release                = stp_policy_node_release,
 191};
 192
 193CONFIGFS_ATTR(stp_policy_node_, masters);
 194CONFIGFS_ATTR(stp_policy_node_, channels);
 195
 196static struct configfs_attribute *stp_policy_node_attrs[] = {
 197        &stp_policy_node_attr_masters,
 198        &stp_policy_node_attr_channels,
 199        NULL,
 200};
 201
 202static const struct config_item_type stp_policy_type;
 203static const struct config_item_type stp_policy_node_type;
 204
 205const struct config_item_type *
 206get_policy_node_type(struct configfs_attribute **attrs)
 207{
 208        struct config_item_type *type;
 209        struct configfs_attribute **merged;
 210
 211        type = kmemdup(&stp_policy_node_type, sizeof(stp_policy_node_type),
 212                       GFP_KERNEL);
 213        if (!type)
 214                return NULL;
 215
 216        merged = memcat_p(stp_policy_node_attrs, attrs);
 217        if (!merged) {
 218                kfree(type);
 219                return NULL;
 220        }
 221
 222        type->ct_attrs = merged;
 223
 224        return type;
 225}
 226
 227static struct config_group *
 228stp_policy_node_make(struct config_group *group, const char *name)
 229{
 230        const struct config_item_type *type = &stp_policy_node_type;
 231        struct stp_policy_node *policy_node, *parent_node;
 232        const struct stm_protocol_driver *pdrv;
 233        struct stp_policy *policy;
 234
 235        if (group->cg_item.ci_type == &stp_policy_type) {
 236                policy = container_of(group, struct stp_policy, group);
 237        } else {
 238                parent_node = container_of(group, struct stp_policy_node,
 239                                           group);
 240                policy = parent_node->policy;
 241        }
 242
 243        if (!policy->stm)
 244                return ERR_PTR(-ENODEV);
 245
 246        pdrv = policy->stm->pdrv;
 247        policy_node =
 248                kzalloc(offsetof(struct stp_policy_node, priv[pdrv->priv_sz]),
 249                        GFP_KERNEL);
 250        if (!policy_node)
 251                return ERR_PTR(-ENOMEM);
 252
 253        if (pdrv->policy_node_init)
 254                pdrv->policy_node_init((void *)policy_node->priv);
 255
 256        if (policy->stm->pdrv_node_type)
 257                type = policy->stm->pdrv_node_type;
 258
 259        config_group_init_type_name(&policy_node->group, name, type);
 260
 261        policy_node->policy = policy;
 262
 263        /* default values for the attributes */
 264        policy_node->first_master = policy->stm->data->sw_start;
 265        policy_node->last_master = policy->stm->data->sw_end;
 266        policy_node->first_channel = 0;
 267        policy_node->last_channel = policy->stm->data->sw_nchannels - 1;
 268
 269        return &policy_node->group;
 270}
 271
 272static void
 273stp_policy_node_drop(struct config_group *group, struct config_item *item)
 274{
 275        config_item_put(item);
 276}
 277
 278static struct configfs_group_operations stp_policy_node_group_ops = {
 279        .make_group     = stp_policy_node_make,
 280        .drop_item      = stp_policy_node_drop,
 281};
 282
 283static const struct config_item_type stp_policy_node_type = {
 284        .ct_item_ops    = &stp_policy_node_item_ops,
 285        .ct_group_ops   = &stp_policy_node_group_ops,
 286        .ct_attrs       = stp_policy_node_attrs,
 287        .ct_owner       = THIS_MODULE,
 288};
 289
 290/*
 291 * Root group: policies.
 292 */
 293static ssize_t stp_policy_device_show(struct config_item *item,
 294                                      char *page)
 295{
 296        struct stp_policy *policy = to_stp_policy(item);
 297        ssize_t count;
 298
 299        count = sprintf(page, "%s\n",
 300                        (policy && policy->stm) ?
 301                        policy->stm->data->name :
 302                        "<none>");
 303
 304        return count;
 305}
 306
 307CONFIGFS_ATTR_RO(stp_policy_, device);
 308
 309static ssize_t stp_policy_protocol_show(struct config_item *item,
 310                                        char *page)
 311{
 312        struct stp_policy *policy = to_stp_policy(item);
 313        ssize_t count;
 314
 315        count = sprintf(page, "%s\n",
 316                        (policy && policy->stm) ?
 317                        policy->stm->pdrv->name :
 318                        "<none>");
 319
 320        return count;
 321}
 322
 323CONFIGFS_ATTR_RO(stp_policy_, protocol);
 324
 325static struct configfs_attribute *stp_policy_attrs[] = {
 326        &stp_policy_attr_device,
 327        &stp_policy_attr_protocol,
 328        NULL,
 329};
 330
 331void stp_policy_unbind(struct stp_policy *policy)
 332{
 333        struct stm_device *stm = policy->stm;
 334
 335        /*
 336         * stp_policy_release() will not call here if the policy is already
 337         * unbound; other users should not either, as no link exists between
 338         * this policy and anything else in that case
 339         */
 340        if (WARN_ON_ONCE(!policy->stm))
 341                return;
 342
 343        lockdep_assert_held(&stm->policy_mutex);
 344
 345        stm->policy = NULL;
 346        policy->stm = NULL;
 347
 348        stm_put_protocol(stm->pdrv);
 349        stm_put_device(stm);
 350}
 351
 352static void stp_policy_release(struct config_item *item)
 353{
 354        struct stp_policy *policy = to_stp_policy(item);
 355        struct stm_device *stm = policy->stm;
 356
 357        /* a policy *can* be unbound and still exist in configfs tree */
 358        if (!stm)
 359                return;
 360
 361        mutex_lock(&stm->policy_mutex);
 362        stp_policy_unbind(policy);
 363        mutex_unlock(&stm->policy_mutex);
 364
 365        kfree(policy);
 366}
 367
 368static struct configfs_item_operations stp_policy_item_ops = {
 369        .release                = stp_policy_release,
 370};
 371
 372static struct configfs_group_operations stp_policy_group_ops = {
 373        .make_group     = stp_policy_node_make,
 374};
 375
 376static const struct config_item_type stp_policy_type = {
 377        .ct_item_ops    = &stp_policy_item_ops,
 378        .ct_group_ops   = &stp_policy_group_ops,
 379        .ct_attrs       = stp_policy_attrs,
 380        .ct_owner       = THIS_MODULE,
 381};
 382
 383static struct config_group *
 384stp_policy_make(struct config_group *group, const char *name)
 385{
 386        const struct config_item_type *pdrv_node_type;
 387        const struct stm_protocol_driver *pdrv;
 388        char *devname, *proto, *p;
 389        struct config_group *ret;
 390        struct stm_device *stm;
 391        int err;
 392
 393        devname = kasprintf(GFP_KERNEL, "%s", name);
 394        if (!devname)
 395                return ERR_PTR(-ENOMEM);
 396
 397        /*
 398         * node must look like <device_name>.<policy_name>, where
 399         * <device_name> is the name of an existing stm device; may
 400         *               contain dots;
 401         * <policy_name> is an arbitrary string; may not contain dots
 402         * <device_name>:<protocol_name>.<policy_name>
 403         */
 404        p = strrchr(devname, '.');
 405        if (!p) {
 406                kfree(devname);
 407                return ERR_PTR(-EINVAL);
 408        }
 409
 410        *p = '\0';
 411
 412        /*
 413         * look for ":<protocol_name>":
 414         *  + no protocol suffix: fall back to whatever is available;
 415         *  + unknown protocol: fail the whole thing
 416         */
 417        proto = strrchr(devname, ':');
 418        if (proto)
 419                *proto++ = '\0';
 420
 421        stm = stm_find_device(devname);
 422        if (!stm) {
 423                kfree(devname);
 424                return ERR_PTR(-ENODEV);
 425        }
 426
 427        err = stm_lookup_protocol(proto, &pdrv, &pdrv_node_type);
 428        kfree(devname);
 429
 430        if (err) {
 431                stm_put_device(stm);
 432                return ERR_PTR(-ENODEV);
 433        }
 434
 435        mutex_lock(&stm->policy_mutex);
 436        if (stm->policy) {
 437                ret = ERR_PTR(-EBUSY);
 438                goto unlock_policy;
 439        }
 440
 441        stm->policy = kzalloc(sizeof(*stm->policy), GFP_KERNEL);
 442        if (!stm->policy) {
 443                ret = ERR_PTR(-ENOMEM);
 444                goto unlock_policy;
 445        }
 446
 447        config_group_init_type_name(&stm->policy->group, name,
 448                                    &stp_policy_type);
 449
 450        stm->pdrv = pdrv;
 451        stm->pdrv_node_type = pdrv_node_type;
 452        stm->policy->stm = stm;
 453        ret = &stm->policy->group;
 454
 455unlock_policy:
 456        mutex_unlock(&stm->policy_mutex);
 457
 458        if (IS_ERR(ret)) {
 459                /*
 460                 * pdrv and stm->pdrv at this point can be quite different,
 461                 * and only one of them needs to be 'put'
 462                 */
 463                stm_put_protocol(pdrv);
 464                stm_put_device(stm);
 465        }
 466
 467        return ret;
 468}
 469
 470static struct configfs_group_operations stp_policy_root_group_ops = {
 471        .make_group     = stp_policy_make,
 472};
 473
 474static const struct config_item_type stp_policy_root_type = {
 475        .ct_group_ops   = &stp_policy_root_group_ops,
 476        .ct_owner       = THIS_MODULE,
 477};
 478
 479static struct configfs_subsystem stp_policy_subsys = {
 480        .su_group = {
 481                .cg_item = {
 482                        .ci_namebuf     = "stp-policy",
 483                        .ci_type        = &stp_policy_root_type,
 484                },
 485        },
 486};
 487
 488/*
 489 * Lock the policy mutex from the outside
 490 */
 491static struct stp_policy_node *
 492__stp_policy_node_lookup(struct stp_policy *policy, char *s)
 493{
 494        struct stp_policy_node *policy_node, *ret = NULL;
 495        struct list_head *head = &policy->group.cg_children;
 496        struct config_item *item;
 497        char *start, *end = s;
 498
 499        if (list_empty(head))
 500                return NULL;
 501
 502next:
 503        for (;;) {
 504                start = strsep(&end, "/");
 505                if (!start)
 506                        break;
 507
 508                if (!*start)
 509                        continue;
 510
 511                list_for_each_entry(item, head, ci_entry) {
 512                        policy_node = to_stp_policy_node(item);
 513
 514                        if (!strcmp(start,
 515                                    policy_node->group.cg_item.ci_name)) {
 516                                ret = policy_node;
 517
 518                                if (!end)
 519                                        goto out;
 520
 521                                head = &policy_node->group.cg_children;
 522                                goto next;
 523                        }
 524                }
 525                break;
 526        }
 527
 528out:
 529        return ret;
 530}
 531
 532
 533struct stp_policy_node *
 534stp_policy_node_lookup(struct stm_device *stm, char *s)
 535{
 536        struct stp_policy_node *policy_node = NULL;
 537
 538        mutex_lock(&stp_policy_subsys.su_mutex);
 539
 540        mutex_lock(&stm->policy_mutex);
 541        if (stm->policy)
 542                policy_node = __stp_policy_node_lookup(stm->policy, s);
 543        mutex_unlock(&stm->policy_mutex);
 544
 545        if (policy_node)
 546                config_item_get(&policy_node->group.cg_item);
 547        else
 548                mutex_unlock(&stp_policy_subsys.su_mutex);
 549
 550        return policy_node;
 551}
 552
 553void stp_policy_node_put(struct stp_policy_node *policy_node)
 554{
 555        lockdep_assert_held(&stp_policy_subsys.su_mutex);
 556
 557        mutex_unlock(&stp_policy_subsys.su_mutex);
 558        config_item_put(&policy_node->group.cg_item);
 559}
 560
 561int __init stp_configfs_init(void)
 562{
 563        config_group_init(&stp_policy_subsys.su_group);
 564        mutex_init(&stp_policy_subsys.su_mutex);
 565        return configfs_register_subsystem(&stp_policy_subsys);
 566}
 567
 568void __exit stp_configfs_exit(void)
 569{
 570        configfs_unregister_subsystem(&stp_policy_subsys);
 571}
 572