• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 2012, 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 
sptlrpc_target_sec_part(struct obd_device * obd)51 enum 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 }
65 EXPORT_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  */
sptlrpc_parse_flavor(const char * str,struct sptlrpc_flavor * flvr)74 int 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 == NULL || 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 == NULL)
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 
130 err_out:
131 	CERROR("invalid flavor string: %s\n", str);
132 	return -EINVAL;
133 }
134 EXPORT_SYMBOL(sptlrpc_parse_flavor);
135 
136 /****************************************
137  * configure rules		      *
138  ****************************************/
139 
get_default_flavor(struct sptlrpc_flavor * sf)140 static 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 
sptlrpc_rule_init(struct sptlrpc_rule * rule)148 static 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  */
sptlrpc_parse_rule(char * param,struct sptlrpc_rule * rule)161 static 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 == NULL) {
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 
sptlrpc_rule_set_free(struct sptlrpc_rule_set * rset)216 static void sptlrpc_rule_set_free(struct sptlrpc_rule_set *rset)
217 {
218 	LASSERT(rset->srs_nslot ||
219 		(rset->srs_nrule == 0 && rset->srs_rules == NULL));
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  */
sptlrpc_rule_set_expand(struct sptlrpc_rule_set * rset)230 static 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 == NULL)
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 
rule_spec_dir(struct sptlrpc_rule * rule)260 static 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 
rule_spec_net(struct sptlrpc_rule * rule)266 static inline int rule_spec_net(struct sptlrpc_rule *rule)
267 {
268 	return (rule->sr_netid != LNET_NIDNET(LNET_NID_ANY));
269 }
270 
rule_match_dir(struct sptlrpc_rule * r1,struct sptlrpc_rule * r2)271 static 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 
rule_match_net(struct sptlrpc_rule * r1,struct sptlrpc_rule * r2)277 static 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  */
sptlrpc_rule_set_merge(struct sptlrpc_rule_set * rset,struct sptlrpc_rule * rule)287 static 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  */
sptlrpc_rule_set_choose(struct sptlrpc_rule_set * rset,enum lustre_sec_part from,enum lustre_sec_part to,lnet_nid_t nid,struct sptlrpc_flavor * sf)377 static 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 
413 struct 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 
419 struct 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 
429 static struct mutex sptlrpc_conf_lock;
430 static LIST_HEAD(sptlrpc_confs);
431 
is_hex(char c)432 static inline int is_hex(char c)
433 {
434 	return ((c >= '0' && c <= '9') ||
435 		(c >= 'a' && c <= 'f'));
436 }
437 
target2fsname(const char * tgt,char * fsname,int buflen)438 static 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 == NULL)
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 
sptlrpc_conf_free_rsets(struct sptlrpc_conf * conf)463 static 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 
sptlrpc_conf_free(struct sptlrpc_conf * conf)481 static 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 
490 static
sptlrpc_conf_get_tgt(struct sptlrpc_conf * conf,const char * name,int create)491 struct 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 
515 static
sptlrpc_conf_get(const char * fsname,int create)516 struct sptlrpc_conf *sptlrpc_conf_get(const char *fsname,
517 				      int create)
518 {
519 	struct sptlrpc_conf *conf;
520 
521 	list_for_each_entry(conf, &sptlrpc_confs, sc_list) {
522 		if (strcmp(conf->sc_fsname, fsname) == 0)
523 			return conf;
524 	}
525 
526 	if (!create)
527 		return NULL;
528 
529 	conf = kzalloc(sizeof(*conf), GFP_NOFS);
530 	if (!conf)
531 		return NULL;
532 
533 	strcpy(conf->sc_fsname, fsname);
534 	sptlrpc_rule_set_init(&conf->sc_rset);
535 	INIT_LIST_HEAD(&conf->sc_tgts);
536 	list_add(&conf->sc_list, &sptlrpc_confs);
537 
538 	CDEBUG(D_SEC, "create sptlrpc conf %s\n", conf->sc_fsname);
539 	return conf;
540 }
541 
542 /**
543  * caller must hold conf_lock already.
544  */
sptlrpc_conf_merge_rule(struct sptlrpc_conf * conf,const char * target,struct sptlrpc_rule * rule)545 static int sptlrpc_conf_merge_rule(struct sptlrpc_conf *conf,
546 				   const char *target,
547 				   struct sptlrpc_rule *rule)
548 {
549 	struct sptlrpc_conf_tgt *conf_tgt;
550 	struct sptlrpc_rule_set *rule_set;
551 
552 	/* fsname == target means general rules for the whole fs */
553 	if (strcmp(conf->sc_fsname, target) == 0) {
554 		rule_set = &conf->sc_rset;
555 	} else {
556 		conf_tgt = sptlrpc_conf_get_tgt(conf, target, 1);
557 		if (conf_tgt) {
558 			rule_set = &conf_tgt->sct_rset;
559 		} else {
560 			CERROR("out of memory, can't merge rule!\n");
561 			return -ENOMEM;
562 		}
563 	}
564 
565 	return sptlrpc_rule_set_merge(rule_set, rule);
566 }
567 
568 /**
569  * process one LCFG_SPTLRPC_CONF record. if \a conf is NULL, we
570  * find one through the target name in the record inside conf_lock;
571  * otherwise means caller already hold conf_lock.
572  */
__sptlrpc_process_config(struct lustre_cfg * lcfg,struct sptlrpc_conf * conf)573 static int __sptlrpc_process_config(struct lustre_cfg *lcfg,
574 				    struct sptlrpc_conf *conf)
575 {
576 	char *target, *param;
577 	char fsname[MTI_NAME_MAXLEN];
578 	struct sptlrpc_rule rule;
579 	int rc;
580 
581 	target = lustre_cfg_string(lcfg, 1);
582 	if (target == NULL) {
583 		CERROR("missing target name\n");
584 		return -EINVAL;
585 	}
586 
587 	param = lustre_cfg_string(lcfg, 2);
588 	if (param == NULL) {
589 		CERROR("missing parameter\n");
590 		return -EINVAL;
591 	}
592 
593 	CDEBUG(D_SEC, "processing rule: %s.%s\n", target, param);
594 
595 	/* parse rule to make sure the format is correct */
596 	if (strncmp(param, PARAM_SRPC_FLVR, sizeof(PARAM_SRPC_FLVR) - 1) != 0) {
597 		CERROR("Invalid sptlrpc parameter: %s\n", param);
598 		return -EINVAL;
599 	}
600 	param += sizeof(PARAM_SRPC_FLVR) - 1;
601 
602 	rc = sptlrpc_parse_rule(param, &rule);
603 	if (rc)
604 		return -EINVAL;
605 
606 	if (conf == NULL) {
607 		target2fsname(target, fsname, sizeof(fsname));
608 
609 		mutex_lock(&sptlrpc_conf_lock);
610 		conf = sptlrpc_conf_get(fsname, 0);
611 		if (conf == NULL) {
612 			CERROR("can't find conf\n");
613 			rc = -ENOMEM;
614 		} else {
615 			rc = sptlrpc_conf_merge_rule(conf, target, &rule);
616 		}
617 		mutex_unlock(&sptlrpc_conf_lock);
618 	} else {
619 		LASSERT(mutex_is_locked(&sptlrpc_conf_lock));
620 		rc = sptlrpc_conf_merge_rule(conf, target, &rule);
621 	}
622 
623 	if (rc == 0)
624 		conf->sc_modified++;
625 
626 	return rc;
627 }
628 
sptlrpc_process_config(struct lustre_cfg * lcfg)629 int sptlrpc_process_config(struct lustre_cfg *lcfg)
630 {
631 	return __sptlrpc_process_config(lcfg, NULL);
632 }
633 EXPORT_SYMBOL(sptlrpc_process_config);
634 
logname2fsname(const char * logname,char * buf,int buflen)635 static int logname2fsname(const char *logname, char *buf, int buflen)
636 {
637 	char *ptr;
638 	int len;
639 
640 	ptr = strrchr(logname, '-');
641 	if (ptr == NULL || strcmp(ptr, "-sptlrpc")) {
642 		CERROR("%s is not a sptlrpc config log\n", logname);
643 		return -EINVAL;
644 	}
645 
646 	len = min((int) (ptr - logname), buflen - 1);
647 
648 	memcpy(buf, logname, len);
649 	buf[len] = '\0';
650 	return 0;
651 }
652 
sptlrpc_conf_log_update_begin(const char * logname)653 void sptlrpc_conf_log_update_begin(const char *logname)
654 {
655 	struct sptlrpc_conf *conf;
656 	char fsname[16];
657 
658 	if (logname2fsname(logname, fsname, sizeof(fsname)))
659 		return;
660 
661 	mutex_lock(&sptlrpc_conf_lock);
662 
663 	conf = sptlrpc_conf_get(fsname, 0);
664 	if (conf) {
665 		if (conf->sc_local) {
666 			LASSERT(conf->sc_updated == 0);
667 			sptlrpc_conf_free_rsets(conf);
668 		}
669 		conf->sc_modified = 0;
670 	}
671 
672 	mutex_unlock(&sptlrpc_conf_lock);
673 }
674 EXPORT_SYMBOL(sptlrpc_conf_log_update_begin);
675 
676 /**
677  * mark a config log has been updated
678  */
sptlrpc_conf_log_update_end(const char * logname)679 void sptlrpc_conf_log_update_end(const char *logname)
680 {
681 	struct sptlrpc_conf *conf;
682 	char fsname[16];
683 
684 	if (logname2fsname(logname, fsname, sizeof(fsname)))
685 		return;
686 
687 	mutex_lock(&sptlrpc_conf_lock);
688 
689 	conf = sptlrpc_conf_get(fsname, 0);
690 	if (conf) {
691 		/*
692 		 * if original state is not updated, make sure the
693 		 * modified counter > 0 to enforce updating local copy.
694 		 */
695 		if (conf->sc_updated == 0)
696 			conf->sc_modified++;
697 
698 		conf->sc_updated = 1;
699 	}
700 
701 	mutex_unlock(&sptlrpc_conf_lock);
702 }
703 EXPORT_SYMBOL(sptlrpc_conf_log_update_end);
704 
sptlrpc_conf_log_start(const char * logname)705 void sptlrpc_conf_log_start(const char *logname)
706 {
707 	char fsname[16];
708 
709 	if (logname2fsname(logname, fsname, sizeof(fsname)))
710 		return;
711 
712 	mutex_lock(&sptlrpc_conf_lock);
713 	sptlrpc_conf_get(fsname, 1);
714 	mutex_unlock(&sptlrpc_conf_lock);
715 }
716 EXPORT_SYMBOL(sptlrpc_conf_log_start);
717 
sptlrpc_conf_log_stop(const char * logname)718 void sptlrpc_conf_log_stop(const char *logname)
719 {
720 	struct sptlrpc_conf *conf;
721 	char fsname[16];
722 
723 	if (logname2fsname(logname, fsname, sizeof(fsname)))
724 		return;
725 
726 	mutex_lock(&sptlrpc_conf_lock);
727 	conf = sptlrpc_conf_get(fsname, 0);
728 	if (conf)
729 		sptlrpc_conf_free(conf);
730 	mutex_unlock(&sptlrpc_conf_lock);
731 }
732 EXPORT_SYMBOL(sptlrpc_conf_log_stop);
733 
flavor_set_flags(struct sptlrpc_flavor * sf,enum lustre_sec_part from,enum lustre_sec_part to,unsigned int fl_udesc)734 static inline void flavor_set_flags(struct sptlrpc_flavor *sf,
735 				    enum lustre_sec_part from,
736 				    enum lustre_sec_part to,
737 				    unsigned int fl_udesc)
738 {
739 	/*
740 	 * null flavor doesn't need to set any flavor, and in fact
741 	 * we'd better not do that because everybody share a single sec.
742 	 */
743 	if (sf->sf_rpc == SPTLRPC_FLVR_NULL)
744 		return;
745 
746 	if (from == LUSTRE_SP_MDT) {
747 		/* MDT->MDT; MDT->OST */
748 		sf->sf_flags |= PTLRPC_SEC_FL_ROOTONLY;
749 	} else if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_OST) {
750 		/* CLI->OST */
751 		sf->sf_flags |= PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_BULK;
752 	} else if (from == LUSTRE_SP_CLI && to == LUSTRE_SP_MDT) {
753 		/* CLI->MDT */
754 		if (fl_udesc && sf->sf_rpc != SPTLRPC_FLVR_NULL)
755 			sf->sf_flags |= PTLRPC_SEC_FL_UDESC;
756 	}
757 }
758 
sptlrpc_conf_choose_flavor(enum lustre_sec_part from,enum lustre_sec_part to,struct obd_uuid * target,lnet_nid_t nid,struct sptlrpc_flavor * sf)759 void sptlrpc_conf_choose_flavor(enum lustre_sec_part from,
760 				enum lustre_sec_part to,
761 				struct obd_uuid *target,
762 				lnet_nid_t nid,
763 				struct sptlrpc_flavor *sf)
764 {
765 	struct sptlrpc_conf *conf;
766 	struct sptlrpc_conf_tgt *conf_tgt;
767 	char name[MTI_NAME_MAXLEN];
768 	int len, rc = 0;
769 
770 	target2fsname(target->uuid, name, sizeof(name));
771 
772 	mutex_lock(&sptlrpc_conf_lock);
773 
774 	conf = sptlrpc_conf_get(name, 0);
775 	if (conf == NULL)
776 		goto out;
777 
778 	/* convert uuid name (supposed end with _UUID) to target name */
779 	len = strlen(target->uuid);
780 	LASSERT(len > 5);
781 	memcpy(name, target->uuid, len - 5);
782 	name[len - 5] = '\0';
783 
784 	conf_tgt = sptlrpc_conf_get_tgt(conf, name, 0);
785 	if (conf_tgt) {
786 		rc = sptlrpc_rule_set_choose(&conf_tgt->sct_rset,
787 					     from, to, nid, sf);
788 		if (rc)
789 			goto out;
790 	}
791 
792 	rc = sptlrpc_rule_set_choose(&conf->sc_rset, from, to, nid, sf);
793 out:
794 	mutex_unlock(&sptlrpc_conf_lock);
795 
796 	if (rc == 0)
797 		get_default_flavor(sf);
798 
799 	flavor_set_flags(sf, from, to, 1);
800 }
801 
802 #define SEC_ADAPT_DELAY	 (10)
803 
804 /**
805  * called by client devices, notify the sptlrpc config has changed and
806  * do import_sec_adapt later.
807  */
sptlrpc_conf_client_adapt(struct obd_device * obd)808 void sptlrpc_conf_client_adapt(struct obd_device *obd)
809 {
810 	struct obd_import *imp;
811 
812 	LASSERT(strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) == 0 ||
813 		strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) == 0);
814 	CDEBUG(D_SEC, "obd %s\n", obd->u.cli.cl_target_uuid.uuid);
815 
816 	/* serialize with connect/disconnect import */
817 	down_read(&obd->u.cli.cl_sem);
818 
819 	imp = obd->u.cli.cl_import;
820 	if (imp) {
821 		spin_lock(&imp->imp_lock);
822 		if (imp->imp_sec)
823 			imp->imp_sec_expire = ktime_get_real_seconds() +
824 				SEC_ADAPT_DELAY;
825 		spin_unlock(&imp->imp_lock);
826 	}
827 
828 	up_read(&obd->u.cli.cl_sem);
829 }
830 EXPORT_SYMBOL(sptlrpc_conf_client_adapt);
831 
sptlrpc_conf_init(void)832 int sptlrpc_conf_init(void)
833 {
834 	mutex_init(&sptlrpc_conf_lock);
835 	return 0;
836 }
837 
sptlrpc_conf_fini(void)838 void sptlrpc_conf_fini(void)
839 {
840 	struct sptlrpc_conf *conf, *conf_next;
841 
842 	mutex_lock(&sptlrpc_conf_lock);
843 	list_for_each_entry_safe(conf, conf_next, &sptlrpc_confs, sc_list) {
844 		sptlrpc_conf_free(conf);
845 	}
846 	LASSERT(list_empty(&sptlrpc_confs));
847 	mutex_unlock(&sptlrpc_conf_lock);
848 }
849