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