linux/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * GPL HEADER START
   4 *
   5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 only,
   9 * as published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful, but
  12 * WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * General Public License version 2 for more details (a copy is included
  15 * in the LICENSE file that accompanied this code).
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * version 2 along with this program; If not, see
  19 * http://www.gnu.org/licenses/gpl-2.0.html
  20 *
  21 * GPL HEADER END
  22 */
  23/*
  24 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  25 * Use is subject to license terms.
  26 *
  27 * Copyright (c) 2011, 2015, Intel Corporation.
  28 */
  29/*
  30 * This file is part of Lustre, http://www.lustre.org/
  31 * Lustre is a trademark of Sun Microsystems, Inc.
  32 */
  33
  34#define DEBUG_SUBSYSTEM S_SEC
  35
  36#include <linux/libcfs/libcfs.h>
  37#include <linux/crypto.h>
  38#include <linux/key.h>
  39
  40#include <obd.h>
  41#include <obd_class.h>
  42#include <obd_support.h>
  43#include <lustre_import.h>
  44#include <uapi/linux/lustre/lustre_param.h>
  45#include <lustre_sec.h>
  46
  47#include "ptlrpc_internal.h"
  48
  49enum lustre_sec_part sptlrpc_target_sec_part(struct obd_device *obd)
  50{
  51        const char *type = obd->obd_type->typ_name;
  52
  53        if (!strcmp(type, LUSTRE_MDT_NAME))
  54                return LUSTRE_SP_MDT;
  55        if (!strcmp(type, LUSTRE_OST_NAME))
  56                return LUSTRE_SP_OST;
  57        if (!strcmp(type, LUSTRE_MGS_NAME))
  58                return LUSTRE_SP_MGS;
  59
  60        CERROR("unknown target %p(%s)\n", obd, type);
  61        return LUSTRE_SP_ANY;
  62}
  63
  64/****************************************
  65 * user supplied flavor string parsing  *
  66 ****************************************/
  67
  68/*
  69 * format: <base_flavor>[-<bulk_type:alg_spec>]
  70 */
  71int sptlrpc_parse_flavor(const char *str, struct sptlrpc_flavor *flvr)
  72{
  73        char buf[32];
  74        char *bulk, *alg;
  75
  76        memset(flvr, 0, sizeof(*flvr));
  77
  78        if (!str || str[0] == '\0') {
  79                flvr->sf_rpc = SPTLRPC_FLVR_INVALID;
  80                return 0;
  81        }
  82
  83        strlcpy(buf, str, sizeof(buf));
  84
  85        bulk = strchr(buf, '-');
  86        if (bulk)
  87                *bulk++ = '\0';
  88
  89        flvr->sf_rpc = sptlrpc_name2flavor_base(buf);
  90        if (flvr->sf_rpc == SPTLRPC_FLVR_INVALID)
  91                goto err_out;
  92
  93        /*
  94         * currently only base flavor "plain" can have bulk specification.
  95         */
  96        if (flvr->sf_rpc == SPTLRPC_FLVR_PLAIN) {
  97                flvr->u_bulk.hash.hash_alg = BULK_HASH_ALG_ADLER32;
  98                if (bulk) {
  99                        /*
 100                         * format: plain-hash:<hash_alg>
 101                         */
 102                        alg = strchr(bulk, ':');
 103                        if (!alg)
 104                                goto err_out;
 105                        *alg++ = '\0';
 106
 107                        if (strcmp(bulk, "hash"))
 108                                goto err_out;
 109
 110                        flvr->u_bulk.hash.hash_alg = sptlrpc_get_hash_alg(alg);
 111                        if (flvr->u_bulk.hash.hash_alg >= BULK_HASH_ALG_MAX)
 112                                goto err_out;
 113                }
 114
 115                if (flvr->u_bulk.hash.hash_alg == BULK_HASH_ALG_NULL)
 116                        flvr_set_bulk_svc(&flvr->sf_rpc, SPTLRPC_BULK_SVC_NULL);
 117                else
 118                        flvr_set_bulk_svc(&flvr->sf_rpc, SPTLRPC_BULK_SVC_INTG);
 119        } else {
 120                if (bulk)
 121                        goto err_out;
 122        }
 123
 124        flvr->sf_flags = 0;
 125        return 0;
 126
 127err_out:
 128        CERROR("invalid flavor string: %s\n", str);
 129        return -EINVAL;
 130}
 131EXPORT_SYMBOL(sptlrpc_parse_flavor);
 132
 133/****************************************
 134 * configure rules                    *
 135 ****************************************/
 136
 137static void get_default_flavor(struct sptlrpc_flavor *sf)
 138{
 139        memset(sf, 0, sizeof(*sf));
 140
 141        sf->sf_rpc = SPTLRPC_FLVR_NULL;
 142        sf->sf_flags = 0;
 143}
 144
 145static void sptlrpc_rule_init(struct sptlrpc_rule *rule)
 146{
 147        rule->sr_netid = LNET_NIDNET(LNET_NID_ANY);
 148        rule->sr_from = LUSTRE_SP_ANY;
 149        rule->sr_to = LUSTRE_SP_ANY;
 150        rule->sr_padding = 0;
 151
 152        get_default_flavor(&rule->sr_flvr);
 153}
 154
 155/*
 156 * format: network[.direction]=flavor
 157 */
 158static int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule)
 159{
 160        char *flavor, *dir;
 161        int rc;
 162
 163        sptlrpc_rule_init(rule);
 164
 165        flavor = strchr(param, '=');
 166        if (!flavor) {
 167                CERROR("invalid param, no '='\n");
 168                return -EINVAL;
 169        }
 170        *flavor++ = '\0';
 171
 172        dir = strchr(param, '.');
 173        if (dir)
 174                *dir++ = '\0';
 175
 176        /* 1.1 network */
 177        if (strcmp(param, "default")) {
 178                rule->sr_netid = libcfs_str2net(param);
 179                if (rule->sr_netid == LNET_NIDNET(LNET_NID_ANY)) {
 180                        CERROR("invalid network name: %s\n", param);
 181                        return -EINVAL;
 182                }
 183        }
 184
 185        /* 1.2 direction */
 186        if (dir) {
 187                if (!strcmp(dir, "mdt2ost")) {
 188                        rule->sr_from = LUSTRE_SP_MDT;
 189                        rule->sr_to = LUSTRE_SP_OST;
 190                } else if (!strcmp(dir, "mdt2mdt")) {
 191                        rule->sr_from = LUSTRE_SP_MDT;
 192                        rule->sr_to = LUSTRE_SP_MDT;
 193                } else if (!strcmp(dir, "cli2ost")) {
 194                        rule->sr_from = LUSTRE_SP_CLI;
 195                        rule->sr_to = LUSTRE_SP_OST;
 196                } else if (!strcmp(dir, "cli2mdt")) {
 197                        rule->sr_from = LUSTRE_SP_CLI;
 198                        rule->sr_to = LUSTRE_SP_MDT;
 199                } else {
 200                        CERROR("invalid rule dir segment: %s\n", dir);
 201                        return -EINVAL;
 202                }
 203        }
 204
 205        /* 2.1 flavor */
 206        rc = sptlrpc_parse_flavor(flavor, &rule->sr_flvr);
 207        if (rc)
 208                return -EINVAL;
 209
 210        return 0;
 211}
 212
 213static void sptlrpc_rule_set_free(struct sptlrpc_rule_set *rset)
 214{
 215        LASSERT(rset->srs_nslot ||
 216                (rset->srs_nrule == 0 && !rset->srs_rules));
 217
 218        if (rset->srs_nslot) {
 219                kfree(rset->srs_rules);
 220                sptlrpc_rule_set_init(rset);
 221        }
 222}
 223
 224/*
 225 * return 0 if the rule set could accommodate one more rule.
 226 */
 227static int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *rset)
 228{
 229        struct sptlrpc_rule *rules;
 230        int nslot;
 231
 232        might_sleep();
 233
 234        if (rset->srs_nrule < rset->srs_nslot)
 235                return 0;
 236
 237        nslot = rset->srs_nslot + 8;
 238
 239        /* better use realloc() if available */
 240        rules = kcalloc(nslot, sizeof(*rset->srs_rules), GFP_NOFS);
 241        if (!rules)
 242                return -ENOMEM;
 243
 244        if (rset->srs_nrule) {
 245                LASSERT(rset->srs_nslot && rset->srs_rules);
 246                memcpy(rules, rset->srs_rules,
 247                       rset->srs_nrule * sizeof(*rset->srs_rules));
 248
 249                kfree(rset->srs_rules);
 250        }
 251
 252        rset->srs_rules = rules;
 253        rset->srs_nslot = nslot;
 254        return 0;
 255}
 256
 257static inline int rule_spec_dir(struct sptlrpc_rule *rule)
 258{
 259        return (rule->sr_from != LUSTRE_SP_ANY ||
 260                rule->sr_to != LUSTRE_SP_ANY);
 261}
 262
 263static inline int rule_spec_net(struct sptlrpc_rule *rule)
 264{
 265        return (rule->sr_netid != LNET_NIDNET(LNET_NID_ANY));
 266}
 267
 268static inline int rule_match_dir(struct sptlrpc_rule *r1,
 269                                 struct sptlrpc_rule *r2)
 270{
 271        return (r1->sr_from == r2->sr_from && r1->sr_to == r2->sr_to);
 272}
 273
 274static inline int rule_match_net(struct sptlrpc_rule *r1,
 275                                 struct sptlrpc_rule *r2)
 276{
 277        return (r1->sr_netid == r2->sr_netid);
 278}
 279
 280/*
 281 * merge @rule into @rset.
 282 * the @rset slots might be expanded.
 283 */
 284static int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset,
 285                                  struct sptlrpc_rule *rule)
 286{
 287        struct sptlrpc_rule *p = rset->srs_rules;
 288        int spec_dir, spec_net;
 289        int rc, n, match = 0;
 290
 291        might_sleep();
 292
 293        spec_net = rule_spec_net(rule);
 294        spec_dir = rule_spec_dir(rule);
 295
 296        for (n = 0; n < rset->srs_nrule; n++) {
 297                p = &rset->srs_rules[n];
 298
 299                /* test network match, if failed:
 300                 * - spec rule: skip rules which is also spec rule match, until
 301                 *   we hit a wild rule, which means no more chance
 302                 * - wild rule: skip until reach the one which is also wild
 303                 *   and matches
 304                 */
 305                if (!rule_match_net(p, rule)) {
 306                        if (spec_net) {
 307                                if (rule_spec_net(p))
 308                                        continue;
 309                                else
 310                                        break;
 311                        } else {
 312                                continue;
 313                        }
 314                }
 315
 316                /* test dir match, same logic as net matching */
 317                if (!rule_match_dir(p, rule)) {
 318                        if (spec_dir) {
 319                                if (rule_spec_dir(p))
 320                                        continue;
 321                                else
 322                                        break;
 323                        } else {
 324                                continue;
 325                        }
 326                }
 327
 328                /* find a match */
 329                match = 1;
 330                break;
 331        }
 332
 333        if (match) {
 334                LASSERT(n >= 0 && n < rset->srs_nrule);
 335
 336                if (rule->sr_flvr.sf_rpc == SPTLRPC_FLVR_INVALID) {
 337                        /* remove this rule */
 338                        if (n < rset->srs_nrule - 1)
 339                                memmove(&rset->srs_rules[n],
 340                                        &rset->srs_rules[n + 1],
 341                                        (rset->srs_nrule - n - 1) *
 342                                        sizeof(*rule));
 343                        rset->srs_nrule--;
 344                } else {
 345                        /* override the rule */
 346                        memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
 347                }
 348        } else {
 349                LASSERT(n >= 0 && n <= rset->srs_nrule);
 350
 351                if (rule->sr_flvr.sf_rpc != SPTLRPC_FLVR_INVALID) {
 352                        rc = sptlrpc_rule_set_expand(rset);
 353                        if (rc)
 354                                return rc;
 355
 356                        if (n < rset->srs_nrule)
 357                                memmove(&rset->srs_rules[n + 1],
 358                                        &rset->srs_rules[n],
 359                                        (rset->srs_nrule - n) * sizeof(*rule));
 360                        memcpy(&rset->srs_rules[n], rule, sizeof(*rule));
 361                        rset->srs_nrule++;
 362                } else {
 363                        CDEBUG(D_CONFIG, "ignore the unmatched deletion\n");
 364                }
 365        }
 366
 367        return 0;
 368}
 369
 370/**
 371 * given from/to/nid, determine a matching flavor in ruleset.
 372 * return 1 if a match found, otherwise return 0.
 373 */
 374static int sptlrpc_rule_set_choose(struct sptlrpc_rule_set *rset,
 375                                   enum lustre_sec_part from,
 376                                   enum lustre_sec_part to,
 377                                   lnet_nid_t nid,
 378                                   struct sptlrpc_flavor *sf)
 379{
 380        struct sptlrpc_rule *r;
 381        int n;
 382
 383        for (n = 0; n < rset->srs_nrule; n++) {
 384                r = &rset->srs_rules[n];
 385
 386                if (LNET_NIDNET(nid) != LNET_NIDNET(LNET_NID_ANY) &&
 387                    r->sr_netid != LNET_NIDNET(LNET_NID_ANY) &&
 388                    LNET_NIDNET(nid) != r->sr_netid)
 389                        continue;
 390
 391                if (from != LUSTRE_SP_ANY && r->sr_from != LUSTRE_SP_ANY &&
 392                    from != r->sr_from)
 393                        continue;
 394
 395                if (to != LUSTRE_SP_ANY && r->sr_to != LUSTRE_SP_ANY &&
 396                    to != r->sr_to)
 397                        continue;
 398
 399                *sf = r->sr_flvr;
 400                return 1;
 401        }
 402
 403        return 0;
 404}
 405
 406/**********************************
 407 * sptlrpc configuration support  *
 408 **********************************/
 409
 410struct sptlrpc_conf_tgt {
 411        struct list_head              sct_list;
 412        char                sct_name[MAX_OBD_NAME];
 413        struct sptlrpc_rule_set sct_rset;
 414};
 415
 416struct sptlrpc_conf {
 417        struct list_head              sc_list;
 418        char                sc_fsname[MTI_NAME_MAXLEN];
 419        unsigned int        sc_modified;  /* modified during updating */
 420        unsigned int        sc_updated:1, /* updated copy from MGS */
 421                                sc_local:1;   /* local copy from target */
 422        struct sptlrpc_rule_set sc_rset;      /* fs general rules */
 423        struct list_head              sc_tgts;      /* target-specific rules */
 424};
 425
 426static struct mutex sptlrpc_conf_lock;
 427static LIST_HEAD(sptlrpc_confs);
 428
 429static inline int is_hex(char c)
 430{
 431        return ((c >= '0' && c <= '9') ||
 432                (c >= 'a' && c <= 'f'));
 433}
 434
 435static void target2fsname(const char *tgt, char *fsname, int buflen)
 436{
 437        const char *ptr;
 438        int len;
 439
 440        ptr = strrchr(tgt, '-');
 441        if (ptr) {
 442                if ((strncmp(ptr, "-MDT", 4) != 0 &&
 443                     strncmp(ptr, "-OST", 4) != 0) ||
 444                    !is_hex(ptr[4]) || !is_hex(ptr[5]) ||
 445                    !is_hex(ptr[6]) || !is_hex(ptr[7]))
 446                        ptr = NULL;
 447        }
 448
 449        /* if we didn't find the pattern, treat the whole string as fsname */
 450        if (!ptr)
 451                len = strlen(tgt);
 452        else
 453                len = ptr - tgt;
 454
 455        len = min(len, buflen - 1);
 456        memcpy(fsname, tgt, len);
 457        fsname[len] = '\0';
 458}
 459
 460static void sptlrpc_conf_free_rsets(struct sptlrpc_conf *conf)
 461{
 462        struct sptlrpc_conf_tgt *conf_tgt, *conf_tgt_next;
 463
 464        sptlrpc_rule_set_free(&conf->sc_rset);
 465
 466        list_for_each_entry_safe(conf_tgt, conf_tgt_next,
 467                                 &conf->sc_tgts, sct_list) {
 468                sptlrpc_rule_set_free(&conf_tgt->sct_rset);
 469                list_del(&conf_tgt->sct_list);
 470                kfree(conf_tgt);
 471        }
 472        LASSERT(list_empty(&conf->sc_tgts));
 473
 474        conf->sc_updated = 0;
 475        conf->sc_local = 0;
 476}
 477
 478static void sptlrpc_conf_free(struct sptlrpc_conf *conf)
 479{
 480        CDEBUG(D_SEC, "free sptlrpc conf %s\n", conf->sc_fsname);
 481
 482        sptlrpc_conf_free_rsets(conf);
 483        list_del(&conf->sc_list);
 484        kfree(conf);
 485}
 486
 487static
 488struct sptlrpc_conf_tgt *sptlrpc_conf_get_tgt(struct sptlrpc_conf *conf,
 489                                              const char *name,
 490                                              int create)
 491{
 492        struct sptlrpc_conf_tgt *conf_tgt;
 493
 494        list_for_each_entry(conf_tgt, &conf->sc_tgts, sct_list) {
 495                if (strcmp(conf_tgt->sct_name, name) == 0)
 496                        return conf_tgt;
 497        }
 498
 499        if (!create)
 500                return NULL;
 501
 502        conf_tgt = kzalloc(sizeof(*conf_tgt), GFP_NOFS);
 503        if (conf_tgt) {
 504                strlcpy(conf_tgt->sct_name, name, sizeof(conf_tgt->sct_name));
 505                sptlrpc_rule_set_init(&conf_tgt->sct_rset);
 506                list_add(&conf_tgt->sct_list, &conf->sc_tgts);
 507        }
 508
 509        return conf_tgt;
 510}
 511
 512static
 513struct sptlrpc_conf *sptlrpc_conf_get(const char *fsname,
 514                                      int create)
 515{
 516        struct sptlrpc_conf *conf;
 517        size_t len;
 518
 519        list_for_each_entry(conf, &sptlrpc_confs, sc_list) {
 520                if (strcmp(conf->sc_fsname, fsname) == 0)
 521                        return conf;
 522        }
 523
 524        if (!create)
 525                return NULL;
 526
 527        conf = kzalloc(sizeof(*conf), GFP_NOFS);
 528        if (!conf)
 529                return NULL;
 530
 531        len = strlcpy(conf->sc_fsname, fsname, sizeof(conf->sc_fsname));
 532        if (len >= sizeof(conf->sc_fsname)) {
 533                kfree(conf);
 534                return NULL;
 535        }
 536        sptlrpc_rule_set_init(&conf->sc_rset);
 537        INIT_LIST_HEAD(&conf->sc_tgts);
 538        list_add(&conf->sc_list, &sptlrpc_confs);
 539
 540        CDEBUG(D_SEC, "create sptlrpc conf %s\n", conf->sc_fsname);
 541        return conf;
 542}
 543
 544/**
 545 * caller must hold conf_lock already.
 546 */
 547static int sptlrpc_conf_merge_rule(struct sptlrpc_conf *conf,
 548                                   const char *target,
 549                                   struct sptlrpc_rule *rule)
 550{
 551        struct sptlrpc_conf_tgt *conf_tgt;
 552        struct sptlrpc_rule_set *rule_set;
 553
 554        /* fsname == target means general rules for the whole fs */
 555        if (strcmp(conf->sc_fsname, target) == 0) {
 556                rule_set = &conf->sc_rset;
 557        } else {
 558                conf_tgt = sptlrpc_conf_get_tgt(conf, target, 1);
 559                if (conf_tgt) {
 560                        rule_set = &conf_tgt->sct_rset;
 561                } else {
 562                        CERROR("out of memory, can't merge rule!\n");
 563                        return -ENOMEM;
 564                }
 565        }
 566
 567        return sptlrpc_rule_set_merge(rule_set, rule);
 568}
 569
 570/**
 571 * process one LCFG_SPTLRPC_CONF record. if \a conf is NULL, we
 572 * find one through the target name in the record inside conf_lock;
 573 * otherwise means caller already hold conf_lock.
 574 */
 575static int __sptlrpc_process_config(struct lustre_cfg *lcfg,
 576                                    struct sptlrpc_conf *conf)
 577{
 578        char *target, *param;
 579        char fsname[MTI_NAME_MAXLEN];
 580        struct sptlrpc_rule rule;
 581        int rc;
 582
 583        target = lustre_cfg_string(lcfg, 1);
 584        if (!target) {
 585                CERROR("missing target name\n");
 586                return -EINVAL;
 587        }
 588
 589        param = lustre_cfg_string(lcfg, 2);
 590        if (!param) {
 591                CERROR("missing parameter\n");
 592                return -EINVAL;
 593        }
 594
 595        CDEBUG(D_SEC, "processing rule: %s.%s\n", target, param);
 596
 597        /* parse rule to make sure the format is correct */
 598        if (strncmp(param, PARAM_SRPC_FLVR, sizeof(PARAM_SRPC_FLVR) - 1) != 0) {
 599                CERROR("Invalid sptlrpc parameter: %s\n", param);
 600                return -EINVAL;
 601        }
 602        param += sizeof(PARAM_SRPC_FLVR) - 1;
 603
 604        rc = sptlrpc_parse_rule(param, &rule);
 605        if (rc)
 606                return -EINVAL;
 607
 608        if (!conf) {
 609                target2fsname(target, fsname, sizeof(fsname));
 610
 611                mutex_lock(&sptlrpc_conf_lock);
 612                conf = sptlrpc_conf_get(fsname, 0);
 613                if (!conf) {
 614                        CERROR("can't find conf\n");
 615                        rc = -ENOMEM;
 616                } else {
 617                        rc = sptlrpc_conf_merge_rule(conf, target, &rule);
 618                }
 619                mutex_unlock(&sptlrpc_conf_lock);
 620        } else {
 621                LASSERT(mutex_is_locked(&sptlrpc_conf_lock));
 622                rc = sptlrpc_conf_merge_rule(conf, target, &rule);
 623        }
 624
 625        if (rc == 0)
 626                conf->sc_modified++;
 627
 628        return rc;
 629}
 630
 631int sptlrpc_process_config(struct lustre_cfg *lcfg)
 632{
 633        return __sptlrpc_process_config(lcfg, NULL);
 634}
 635EXPORT_SYMBOL(sptlrpc_process_config);
 636
 637static int logname2fsname(const char *logname, char *buf, int buflen)
 638{
 639        char *ptr;
 640        int len;
 641
 642        ptr = strrchr(logname, '-');
 643        if (!ptr || strcmp(ptr, "-sptlrpc")) {
 644                CERROR("%s is not a sptlrpc config log\n", logname);
 645                return -EINVAL;
 646        }
 647
 648        len = min((int)(ptr - logname), buflen - 1);
 649
 650        memcpy(buf, logname, len);
 651        buf[len] = '\0';
 652        return 0;
 653}
 654
 655void sptlrpc_conf_log_update_begin(const char *logname)
 656{
 657        struct sptlrpc_conf *conf;
 658        char fsname[16];
 659
 660        if (logname2fsname(logname, fsname, sizeof(fsname)))
 661                return;
 662
 663        mutex_lock(&sptlrpc_conf_lock);
 664
 665        conf = sptlrpc_conf_get(fsname, 0);
 666        if (conf) {
 667                if (conf->sc_local) {
 668                        LASSERT(conf->sc_updated == 0);
 669                        sptlrpc_conf_free_rsets(conf);
 670                }
 671                conf->sc_modified = 0;
 672        }
 673
 674        mutex_unlock(&sptlrpc_conf_lock);
 675}
 676EXPORT_SYMBOL(sptlrpc_conf_log_update_begin);
 677
 678/**
 679 * mark a config log has been updated
 680 */
 681void sptlrpc_conf_log_update_end(const char *logname)
 682{
 683        struct sptlrpc_conf *conf;
 684        char fsname[16];
 685
 686        if (logname2fsname(logname, fsname, sizeof(fsname)))
 687                return;
 688
 689        mutex_lock(&sptlrpc_conf_lock);
 690
 691        conf = sptlrpc_conf_get(fsname, 0);
 692        if (conf) {
 693                /*
 694                 * if original state is not updated, make sure the
 695                 * modified counter > 0 to enforce updating local copy.
 696                 */
 697                if (conf->sc_updated == 0)
 698                        conf->sc_modified++;
 699
 700                conf->sc_updated = 1;
 701        }
 702
 703        mutex_unlock(&sptlrpc_conf_lock);
 704}
 705EXPORT_SYMBOL(sptlrpc_conf_log_update_end);
 706
 707void sptlrpc_conf_log_start(const char *logname)
 708{
 709        char fsname[16];
 710
 711        if (logname2fsname(logname, fsname, sizeof(fsname)))
 712                return;
 713
 714        mutex_lock(&sptlrpc_conf_lock);
 715        sptlrpc_conf_get(fsname, 1);
 716        mutex_unlock(&sptlrpc_conf_lock);
 717}
 718EXPORT_SYMBOL(sptlrpc_conf_log_start);
 719
 720void sptlrpc_conf_log_stop(const char *logname)
 721{
 722        struct sptlrpc_conf *conf;
 723        char fsname[16];
 724
 725        if (logname2fsname(logname, fsname, sizeof(fsname)))
 726                return;
 727
 728        mutex_lock(&sptlrpc_conf_lock);
 729        conf = sptlrpc_conf_get(fsname, 0);
 730        if (conf)
 731                sptlrpc_conf_free(conf);
 732        mutex_unlock(&sptlrpc_conf_lock);
 733}
 734EXPORT_SYMBOL(sptlrpc_conf_log_stop);
 735
 736static inline void flavor_set_flags(struct sptlrpc_flavor *sf,
 737                                    enum lustre_sec_part from,
 738                                    enum lustre_sec_part to,
 739                                    unsigned int fl_udesc)
 740{
 741        /*
 742         * null flavor doesn't need to set any flavor, and in fact
 743         * we'd better not do that because everybody share a single sec.
 744         */
 745        if (sf->sf_rpc == SPTLRPC_FLVR_NULL)
 746                return;
 747
 748        if (from == LUSTRE_SP_MDT) {
 749                /* MDT->MDT; MDT->OST */
 750                sf->sf_flags |= PTLRPC_SEC_FL_ROOTONLY;
 751        } else if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_OST) {
 752                /* CLI->OST */
 753                sf->sf_flags |= PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_BULK;
 754        } else if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_MDT) {
 755                /* CLI->MDT */
 756                if (fl_udesc && sf->sf_rpc != SPTLRPC_FLVR_NULL)
 757                        sf->sf_flags |= PTLRPC_SEC_FL_UDESC;
 758        }
 759}
 760
 761void sptlrpc_conf_choose_flavor(enum lustre_sec_part from,
 762                                enum lustre_sec_part to,
 763                                struct obd_uuid *target,
 764                                lnet_nid_t nid,
 765                                struct sptlrpc_flavor *sf)
 766{
 767        struct sptlrpc_conf *conf;
 768        struct sptlrpc_conf_tgt *conf_tgt;
 769        char name[MTI_NAME_MAXLEN];
 770        int len, rc = 0;
 771
 772        target2fsname(target->uuid, name, sizeof(name));
 773
 774        mutex_lock(&sptlrpc_conf_lock);
 775
 776        conf = sptlrpc_conf_get(name, 0);
 777        if (!conf)
 778                goto out;
 779
 780        /* convert uuid name (supposed end with _UUID) to target name */
 781        len = strlen(target->uuid);
 782        LASSERT(len > 5);
 783        memcpy(name, target->uuid, len - 5);
 784        name[len - 5] = '\0';
 785
 786        conf_tgt = sptlrpc_conf_get_tgt(conf, name, 0);
 787        if (conf_tgt) {
 788                rc = sptlrpc_rule_set_choose(&conf_tgt->sct_rset,
 789                                             from, to, nid, sf);
 790                if (rc)
 791                        goto out;
 792        }
 793
 794        rc = sptlrpc_rule_set_choose(&conf->sc_rset, from, to, nid, sf);
 795out:
 796        mutex_unlock(&sptlrpc_conf_lock);
 797
 798        if (rc == 0)
 799                get_default_flavor(sf);
 800
 801        flavor_set_flags(sf, from, to, 1);
 802}
 803
 804#define SEC_ADAPT_DELAY  (10)
 805
 806/**
 807 * called by client devices, notify the sptlrpc config has changed and
 808 * do import_sec_adapt later.
 809 */
 810void sptlrpc_conf_client_adapt(struct obd_device *obd)
 811{
 812        struct obd_import *imp;
 813
 814        LASSERT(strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) == 0 ||
 815                strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) == 0);
 816        CDEBUG(D_SEC, "obd %s\n", obd->u.cli.cl_target_uuid.uuid);
 817
 818        /* serialize with connect/disconnect import */
 819        down_read_nested(&obd->u.cli.cl_sem, OBD_CLI_SEM_MDCOSC);
 820
 821        imp = obd->u.cli.cl_import;
 822        if (imp) {
 823                spin_lock(&imp->imp_lock);
 824                if (imp->imp_sec)
 825                        imp->imp_sec_expire = ktime_get_real_seconds() +
 826                                SEC_ADAPT_DELAY;
 827                spin_unlock(&imp->imp_lock);
 828        }
 829
 830        up_read(&obd->u.cli.cl_sem);
 831}
 832EXPORT_SYMBOL(sptlrpc_conf_client_adapt);
 833
 834int sptlrpc_conf_init(void)
 835{
 836        mutex_init(&sptlrpc_conf_lock);
 837        return 0;
 838}
 839
 840void sptlrpc_conf_fini(void)
 841{
 842        struct sptlrpc_conf *conf, *conf_next;
 843
 844        mutex_lock(&sptlrpc_conf_lock);
 845        list_for_each_entry_safe(conf, conf_next, &sptlrpc_confs, sc_list) {
 846                sptlrpc_conf_free(conf);
 847        }
 848        LASSERT(list_empty(&sptlrpc_confs));
 849        mutex_unlock(&sptlrpc_conf_lock);
 850}
 851