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