Commit | Line | Data |
---|---|---|
d7e09d03 PT |
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 | * | |
1dc563a6 | 30 | * Copyright (c) 2011, 2015, Intel Corporation. |
d7e09d03 PT |
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 | ||
9fdaf8c0 | 39 | #include "../../include/linux/libcfs/libcfs.h" |
d7e09d03 PT |
40 | #include <linux/crypto.h> |
41 | #include <linux/key.h> | |
42 | ||
e27db149 | 43 | #include "../include/obd.h" |
e27db149 | 44 | #include "../include/obd_support.h" |
e27db149 | 45 | #include "../include/lustre_import.h" |
e27db149 GKH |
46 | #include "../include/lustre_param.h" |
47 | #include "../include/lustre_sec.h" | |
d7e09d03 PT |
48 | |
49 | #include "ptlrpc_internal.h" | |
50 | ||
d7e09d03 PT |
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 | */ | |
74 | int sptlrpc_parse_flavor(const char *str, struct sptlrpc_flavor *flvr) | |
75 | { | |
d0bfef31 CH |
76 | char buf[32]; |
77 | char *bulk, *alg; | |
d7e09d03 PT |
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 | ||
9563fe8a | 86 | strlcpy(buf, str, sizeof(buf)); |
d7e09d03 PT |
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 | ||
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 | ||
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 | */ | |
91a3a501 | 161 | static int sptlrpc_parse_rule(char *param, struct sptlrpc_rule *rule) |
d7e09d03 | 162 | { |
d0bfef31 CH |
163 | char *flavor, *dir; |
164 | int rc; | |
d7e09d03 PT |
165 | |
166 | sptlrpc_rule_init(rule); | |
167 | ||
168 | flavor = strchr(param, '='); | |
169 | if (flavor == NULL) { | |
170 | CERROR("invalid param, no '='\n"); | |
0a3bdb00 | 171 | return -EINVAL; |
d7e09d03 PT |
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); | |
0a3bdb00 | 184 | return -EINVAL; |
d7e09d03 PT |
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); | |
0a3bdb00 | 204 | return -EINVAL; |
d7e09d03 PT |
205 | } |
206 | } | |
207 | ||
208 | /* 2.1 flavor */ | |
209 | rc = sptlrpc_parse_flavor(flavor, &rule->sr_flvr); | |
210 | if (rc) | |
0a3bdb00 | 211 | return -EINVAL; |
d7e09d03 | 212 | |
0a3bdb00 | 213 | return 0; |
d7e09d03 | 214 | } |
d7e09d03 | 215 | |
337349fb | 216 | static void sptlrpc_rule_set_free(struct sptlrpc_rule_set *rset) |
d7e09d03 PT |
217 | { |
218 | LASSERT(rset->srs_nslot || | |
219 | (rset->srs_nrule == 0 && rset->srs_rules == NULL)); | |
220 | ||
221 | if (rset->srs_nslot) { | |
9ae10597 | 222 | kfree(rset->srs_rules); |
d7e09d03 PT |
223 | sptlrpc_rule_set_init(rset); |
224 | } | |
225 | } | |
d7e09d03 PT |
226 | |
227 | /* | |
b6da17f3 | 228 | * return 0 if the rule set could accommodate one more rule. |
d7e09d03 | 229 | */ |
57552bf0 | 230 | static int sptlrpc_rule_set_expand(struct sptlrpc_rule_set *rset) |
d7e09d03 PT |
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 */ | |
9ae10597 | 243 | rules = kcalloc(nslot, sizeof(*rset->srs_rules), GFP_NOFS); |
d7e09d03 PT |
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 | ||
9ae10597 | 252 | kfree(rset->srs_rules); |
d7e09d03 PT |
253 | } |
254 | ||
255 | rset->srs_rules = rules; | |
256 | rset->srs_nslot = nslot; | |
257 | return 0; | |
258 | } | |
d7e09d03 PT |
259 | |
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 | } | |
c9f6bb96 | 265 | |
d7e09d03 PT |
266 | static inline int rule_spec_net(struct sptlrpc_rule *rule) |
267 | { | |
268 | return (rule->sr_netid != LNET_NIDNET(LNET_NID_ANY)); | |
269 | } | |
c9f6bb96 | 270 | |
d7e09d03 PT |
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 | } | |
c9f6bb96 | 276 | |
d7e09d03 PT |
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 | */ | |
5cff0cc9 SB |
287 | static int sptlrpc_rule_set_merge(struct sptlrpc_rule_set *rset, |
288 | struct sptlrpc_rule *rule) | |
d7e09d03 | 289 | { |
d0bfef31 CH |
290 | struct sptlrpc_rule *p = rset->srs_rules; |
291 | int spec_dir, spec_net; | |
292 | int rc, n, match = 0; | |
d7e09d03 PT |
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 | } | |
c9f6bb96 | 372 | |
d7e09d03 PT |
373 | /** |
374 | * given from/to/nid, determine a matching flavor in ruleset. | |
375 | * return 1 if a match found, otherwise return 0. | |
376 | */ | |
65e4b792 SB |
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) | |
d7e09d03 | 382 | { |
d0bfef31 CH |
383 | struct sptlrpc_rule *r; |
384 | int n; | |
d7e09d03 PT |
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 | } | |
d7e09d03 | 408 | |
d7e09d03 PT |
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 | ||
432 | static inline int is_hex(char c) | |
433 | { | |
434 | return ((c >= '0' && c <= '9') || | |
435 | (c >= 'a' && c <= 'f')); | |
436 | } | |
437 | ||
438 | static void target2fsname(const char *tgt, char *fsname, int buflen) | |
439 | { | |
d0bfef31 CH |
440 | const char *ptr; |
441 | int len; | |
d7e09d03 PT |
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 | ||
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); | |
9ae10597 | 473 | kfree(conf_tgt); |
d7e09d03 PT |
474 | } |
475 | LASSERT(list_empty(&conf->sc_tgts)); | |
476 | ||
477 | conf->sc_updated = 0; | |
478 | conf->sc_local = 0; | |
479 | } | |
480 | ||
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); | |
9ae10597 | 487 | kfree(conf); |
d7e09d03 PT |
488 | } |
489 | ||
490 | static | |
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 | ||
9ae10597 | 505 | conf_tgt = kzalloc(sizeof(*conf_tgt), GFP_NOFS); |
d7e09d03 PT |
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 | |
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 | ||
9ae10597 | 529 | conf = kzalloc(sizeof(*conf), GFP_NOFS); |
597851ac | 530 | if (!conf) |
d7e09d03 PT |
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 | */ | |
545 | static int sptlrpc_conf_merge_rule(struct sptlrpc_conf *conf, | |
546 | const char *target, | |
547 | struct sptlrpc_rule *rule) | |
548 | { | |
d0bfef31 CH |
549 | struct sptlrpc_conf_tgt *conf_tgt; |
550 | struct sptlrpc_rule_set *rule_set; | |
d7e09d03 PT |
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 | */ | |
573 | static int __sptlrpc_process_config(struct lustre_cfg *lcfg, | |
574 | struct sptlrpc_conf *conf) | |
575 | { | |
d0bfef31 CH |
576 | char *target, *param; |
577 | char fsname[MTI_NAME_MAXLEN]; | |
578 | struct sptlrpc_rule rule; | |
579 | int rc; | |
d7e09d03 PT |
580 | |
581 | target = lustre_cfg_string(lcfg, 1); | |
582 | if (target == NULL) { | |
583 | CERROR("missing target name\n"); | |
0a3bdb00 | 584 | return -EINVAL; |
d7e09d03 PT |
585 | } |
586 | ||
587 | param = lustre_cfg_string(lcfg, 2); | |
588 | if (param == NULL) { | |
589 | CERROR("missing parameter\n"); | |
0a3bdb00 | 590 | return -EINVAL; |
d7e09d03 PT |
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); | |
0a3bdb00 | 598 | return -EINVAL; |
d7e09d03 PT |
599 | } |
600 | param += sizeof(PARAM_SRPC_FLVR) - 1; | |
601 | ||
602 | rc = sptlrpc_parse_rule(param, &rule); | |
603 | if (rc) | |
0a3bdb00 | 604 | return -EINVAL; |
d7e09d03 PT |
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 | ||
0a3bdb00 | 626 | return rc; |
d7e09d03 PT |
627 | } |
628 | ||
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 | ||
635 | static int logname2fsname(const char *logname, char *buf, int buflen) | |
636 | { | |
d0bfef31 CH |
637 | char *ptr; |
638 | int len; | |
d7e09d03 PT |
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 | ||
653 | void sptlrpc_conf_log_update_begin(const char *logname) | |
654 | { | |
655 | struct sptlrpc_conf *conf; | |
d0bfef31 | 656 | char fsname[16]; |
d7e09d03 PT |
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); | |
fe456ff4 | 664 | if (conf) { |
a58a38ac | 665 | if (conf->sc_local) { |
fe456ff4 RS |
666 | LASSERT(conf->sc_updated == 0); |
667 | sptlrpc_conf_free_rsets(conf); | |
668 | } | |
669 | conf->sc_modified = 0; | |
d7e09d03 | 670 | } |
d7e09d03 PT |
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 | */ | |
679 | void sptlrpc_conf_log_update_end(const char *logname) | |
680 | { | |
681 | struct sptlrpc_conf *conf; | |
d0bfef31 | 682 | char fsname[16]; |
d7e09d03 PT |
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 | ||
705 | void sptlrpc_conf_log_start(const char *logname) | |
706 | { | |
d0bfef31 | 707 | char fsname[16]; |
d7e09d03 PT |
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 | ||
718 | void sptlrpc_conf_log_stop(const char *logname) | |
719 | { | |
720 | struct sptlrpc_conf *conf; | |
d0bfef31 | 721 | char fsname[16]; |
d7e09d03 PT |
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 | ||
dc13eb86 | 734 | static inline void flavor_set_flags(struct sptlrpc_flavor *sf, |
d7e09d03 PT |
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 | ||
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 | { | |
d0bfef31 | 765 | struct sptlrpc_conf *conf; |
d7e09d03 | 766 | struct sptlrpc_conf_tgt *conf_tgt; |
d0bfef31 CH |
767 | char name[MTI_NAME_MAXLEN]; |
768 | int len, rc = 0; | |
d7e09d03 PT |
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 | ||
d7e09d03 PT |
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 | */ | |
808 | void sptlrpc_conf_client_adapt(struct obd_device *obd) | |
809 | { | |
d0bfef31 | 810 | struct obd_import *imp; |
d7e09d03 PT |
811 | |
812 | LASSERT(strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) == 0 || | |
b533ff4b | 813 | strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) == 0); |
d7e09d03 PT |
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) | |
986ef135 | 823 | imp->imp_sec_expire = ktime_get_real_seconds() + |
d7e09d03 PT |
824 | SEC_ADAPT_DELAY; |
825 | spin_unlock(&imp->imp_lock); | |
826 | } | |
827 | ||
828 | up_read(&obd->u.cli.cl_sem); | |
d7e09d03 PT |
829 | } |
830 | EXPORT_SYMBOL(sptlrpc_conf_client_adapt); | |
831 | ||
d0bfef31 | 832 | int sptlrpc_conf_init(void) |
d7e09d03 PT |
833 | { |
834 | mutex_init(&sptlrpc_conf_lock); | |
835 | return 0; | |
836 | } | |
837 | ||
838 | void sptlrpc_conf_fini(void) | |
839 | { | |
d0bfef31 | 840 | struct sptlrpc_conf *conf, *conf_next; |
d7e09d03 PT |
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 | } |