1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <linux/ceph/ceph_debug.h> 4 #include <linux/backing-dev.h> 5 #include <linux/ctype.h> 6 #include <linux/fs.h> 7 #include <linux/inet.h> 8 #include <linux/in6.h> 9 #include <linux/key.h> 10 #include <keys/ceph-type.h> 11 #include <linux/module.h> 12 #include <linux/mount.h> 13 #include <linux/nsproxy.h> 14 #include <linux/fs_parser.h> 15 #include <linux/sched.h> 16 #include <linux/sched/mm.h> 17 #include <linux/seq_file.h> 18 #include <linux/slab.h> 19 #include <linux/statfs.h> 20 #include <linux/string.h> 21 #include <linux/vmalloc.h> 22 23 24 #include <linux/ceph/ceph_features.h> 25 #include <linux/ceph/libceph.h> 26 #include <linux/ceph/debugfs.h> 27 #include <linux/ceph/decode.h> 28 #include <linux/ceph/mon_client.h> 29 #include <linux/ceph/auth.h> 30 #include "crypto.h" 31 32 33 /* 34 * Module compatibility interface. For now it doesn't do anything, 35 * but its existence signals a certain level of functionality. 36 * 37 * The data buffer is used to pass information both to and from 38 * libceph. The return value indicates whether libceph determines 39 * it is compatible with the caller (from another kernel module), 40 * given the provided data. 41 * 42 * The data pointer can be null. 43 */ 44 bool libceph_compatible(void *data) 45 { 46 return true; 47 } 48 EXPORT_SYMBOL(libceph_compatible); 49 50 static int param_get_supported_features(char *buffer, 51 const struct kernel_param *kp) 52 { 53 return sprintf(buffer, "0x%llx", CEPH_FEATURES_SUPPORTED_DEFAULT); 54 } 55 static const struct kernel_param_ops param_ops_supported_features = { 56 .get = param_get_supported_features, 57 }; 58 module_param_cb(supported_features, ¶m_ops_supported_features, NULL, 59 0444); 60 61 const char *ceph_msg_type_name(int type) 62 { 63 switch (type) { 64 case CEPH_MSG_SHUTDOWN: return "shutdown"; 65 case CEPH_MSG_PING: return "ping"; 66 case CEPH_MSG_AUTH: return "auth"; 67 case CEPH_MSG_AUTH_REPLY: return "auth_reply"; 68 case CEPH_MSG_MON_MAP: return "mon_map"; 69 case CEPH_MSG_MON_GET_MAP: return "mon_get_map"; 70 case CEPH_MSG_MON_SUBSCRIBE: return "mon_subscribe"; 71 case CEPH_MSG_MON_SUBSCRIBE_ACK: return "mon_subscribe_ack"; 72 case CEPH_MSG_STATFS: return "statfs"; 73 case CEPH_MSG_STATFS_REPLY: return "statfs_reply"; 74 case CEPH_MSG_MON_GET_VERSION: return "mon_get_version"; 75 case CEPH_MSG_MON_GET_VERSION_REPLY: return "mon_get_version_reply"; 76 case CEPH_MSG_MDS_MAP: return "mds_map"; 77 case CEPH_MSG_FS_MAP_USER: return "fs_map_user"; 78 case CEPH_MSG_CLIENT_SESSION: return "client_session"; 79 case CEPH_MSG_CLIENT_RECONNECT: return "client_reconnect"; 80 case CEPH_MSG_CLIENT_REQUEST: return "client_request"; 81 case CEPH_MSG_CLIENT_REQUEST_FORWARD: return "client_request_forward"; 82 case CEPH_MSG_CLIENT_REPLY: return "client_reply"; 83 case CEPH_MSG_CLIENT_CAPS: return "client_caps"; 84 case CEPH_MSG_CLIENT_CAPRELEASE: return "client_cap_release"; 85 case CEPH_MSG_CLIENT_QUOTA: return "client_quota"; 86 case CEPH_MSG_CLIENT_SNAP: return "client_snap"; 87 case CEPH_MSG_CLIENT_LEASE: return "client_lease"; 88 case CEPH_MSG_POOLOP_REPLY: return "poolop_reply"; 89 case CEPH_MSG_POOLOP: return "poolop"; 90 case CEPH_MSG_MON_COMMAND: return "mon_command"; 91 case CEPH_MSG_MON_COMMAND_ACK: return "mon_command_ack"; 92 case CEPH_MSG_OSD_MAP: return "osd_map"; 93 case CEPH_MSG_OSD_OP: return "osd_op"; 94 case CEPH_MSG_OSD_OPREPLY: return "osd_opreply"; 95 case CEPH_MSG_WATCH_NOTIFY: return "watch_notify"; 96 case CEPH_MSG_OSD_BACKOFF: return "osd_backoff"; 97 default: return "unknown"; 98 } 99 } 100 EXPORT_SYMBOL(ceph_msg_type_name); 101 102 /* 103 * Initially learn our fsid, or verify an fsid matches. 104 */ 105 int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid) 106 { 107 if (client->have_fsid) { 108 if (ceph_fsid_compare(&client->fsid, fsid)) { 109 pr_err("bad fsid, had %pU got %pU", 110 &client->fsid, fsid); 111 return -1; 112 } 113 } else { 114 memcpy(&client->fsid, fsid, sizeof(*fsid)); 115 } 116 return 0; 117 } 118 EXPORT_SYMBOL(ceph_check_fsid); 119 120 static int strcmp_null(const char *s1, const char *s2) 121 { 122 if (!s1 && !s2) 123 return 0; 124 if (s1 && !s2) 125 return -1; 126 if (!s1 && s2) 127 return 1; 128 return strcmp(s1, s2); 129 } 130 131 int ceph_compare_options(struct ceph_options *new_opt, 132 struct ceph_client *client) 133 { 134 struct ceph_options *opt1 = new_opt; 135 struct ceph_options *opt2 = client->options; 136 int ofs = offsetof(struct ceph_options, mon_addr); 137 int i; 138 int ret; 139 140 /* 141 * Don't bother comparing options if network namespaces don't 142 * match. 143 */ 144 if (!net_eq(current->nsproxy->net_ns, read_pnet(&client->msgr.net))) 145 return -1; 146 147 ret = memcmp(opt1, opt2, ofs); 148 if (ret) 149 return ret; 150 151 ret = strcmp_null(opt1->name, opt2->name); 152 if (ret) 153 return ret; 154 155 if (opt1->key && !opt2->key) 156 return -1; 157 if (!opt1->key && opt2->key) 158 return 1; 159 if (opt1->key && opt2->key) { 160 if (opt1->key->type != opt2->key->type) 161 return -1; 162 if (opt1->key->created.tv_sec != opt2->key->created.tv_sec) 163 return -1; 164 if (opt1->key->created.tv_nsec != opt2->key->created.tv_nsec) 165 return -1; 166 if (opt1->key->len != opt2->key->len) 167 return -1; 168 if (opt1->key->key && !opt2->key->key) 169 return -1; 170 if (!opt1->key->key && opt2->key->key) 171 return 1; 172 if (opt1->key->key && opt2->key->key) { 173 ret = memcmp(opt1->key->key, opt2->key->key, opt1->key->len); 174 if (ret) 175 return ret; 176 } 177 } 178 179 ret = ceph_compare_crush_locs(&opt1->crush_locs, &opt2->crush_locs); 180 if (ret) 181 return ret; 182 183 /* any matching mon ip implies a match */ 184 for (i = 0; i < opt1->num_mon; i++) { 185 if (ceph_monmap_contains(client->monc.monmap, 186 &opt1->mon_addr[i])) 187 return 0; 188 } 189 return -1; 190 } 191 EXPORT_SYMBOL(ceph_compare_options); 192 193 int ceph_parse_fsid(const char *str, struct ceph_fsid *fsid) 194 { 195 int i = 0; 196 char tmp[3]; 197 int err = -EINVAL; 198 int d; 199 200 dout("%s '%s'\n", __func__, str); 201 tmp[2] = 0; 202 while (*str && i < 16) { 203 if (ispunct(*str)) { 204 str++; 205 continue; 206 } 207 if (!isxdigit(str[0]) || !isxdigit(str[1])) 208 break; 209 tmp[0] = str[0]; 210 tmp[1] = str[1]; 211 if (sscanf(tmp, "%x", &d) < 1) 212 break; 213 fsid->fsid[i] = d & 0xff; 214 i++; 215 str += 2; 216 } 217 218 if (i == 16) 219 err = 0; 220 dout("%s ret %d got fsid %pU\n", __func__, err, fsid); 221 return err; 222 } 223 EXPORT_SYMBOL(ceph_parse_fsid); 224 225 /* 226 * ceph options 227 */ 228 enum { 229 Opt_osdkeepalivetimeout, 230 Opt_mount_timeout, 231 Opt_osd_idle_ttl, 232 Opt_osd_request_timeout, 233 /* int args above */ 234 Opt_fsid, 235 Opt_name, 236 Opt_secret, 237 Opt_key, 238 Opt_ip, 239 Opt_crush_location, 240 Opt_read_from_replica, 241 Opt_ms_mode, 242 /* string args above */ 243 Opt_share, 244 Opt_crc, 245 Opt_cephx_require_signatures, 246 Opt_cephx_sign_messages, 247 Opt_tcp_nodelay, 248 Opt_abort_on_full, 249 Opt_rxbounce, 250 }; 251 252 enum { 253 Opt_read_from_replica_no, 254 Opt_read_from_replica_balance, 255 Opt_read_from_replica_localize, 256 }; 257 258 static const struct constant_table ceph_param_read_from_replica[] = { 259 {"no", Opt_read_from_replica_no}, 260 {"balance", Opt_read_from_replica_balance}, 261 {"localize", Opt_read_from_replica_localize}, 262 {} 263 }; 264 265 enum ceph_ms_mode { 266 Opt_ms_mode_legacy, 267 Opt_ms_mode_crc, 268 Opt_ms_mode_secure, 269 Opt_ms_mode_prefer_crc, 270 Opt_ms_mode_prefer_secure 271 }; 272 273 static const struct constant_table ceph_param_ms_mode[] = { 274 {"legacy", Opt_ms_mode_legacy}, 275 {"crc", Opt_ms_mode_crc}, 276 {"secure", Opt_ms_mode_secure}, 277 {"prefer-crc", Opt_ms_mode_prefer_crc}, 278 {"prefer-secure", Opt_ms_mode_prefer_secure}, 279 {} 280 }; 281 282 static const struct fs_parameter_spec ceph_parameters[] = { 283 fsparam_flag ("abort_on_full", Opt_abort_on_full), 284 __fsparam (NULL, "cephx_require_signatures", Opt_cephx_require_signatures, 285 fs_param_neg_with_no|fs_param_deprecated, NULL), 286 fsparam_flag_no ("cephx_sign_messages", Opt_cephx_sign_messages), 287 fsparam_flag_no ("crc", Opt_crc), 288 fsparam_string ("crush_location", Opt_crush_location), 289 fsparam_string ("fsid", Opt_fsid), 290 fsparam_string ("ip", Opt_ip), 291 fsparam_string ("key", Opt_key), 292 fsparam_u32 ("mount_timeout", Opt_mount_timeout), 293 fsparam_string ("name", Opt_name), 294 fsparam_u32 ("osd_idle_ttl", Opt_osd_idle_ttl), 295 fsparam_u32 ("osd_request_timeout", Opt_osd_request_timeout), 296 fsparam_u32 ("osdkeepalive", Opt_osdkeepalivetimeout), 297 fsparam_enum ("read_from_replica", Opt_read_from_replica, 298 ceph_param_read_from_replica), 299 fsparam_flag ("rxbounce", Opt_rxbounce), 300 fsparam_enum ("ms_mode", Opt_ms_mode, 301 ceph_param_ms_mode), 302 fsparam_string ("secret", Opt_secret), 303 fsparam_flag_no ("share", Opt_share), 304 fsparam_flag_no ("tcp_nodelay", Opt_tcp_nodelay), 305 {} 306 }; 307 308 struct ceph_options *ceph_alloc_options(void) 309 { 310 struct ceph_options *opt; 311 312 opt = kzalloc_obj(*opt, GFP_KERNEL); 313 if (!opt) 314 return NULL; 315 316 opt->crush_locs = RB_ROOT; 317 opt->mon_addr = kzalloc_objs(*opt->mon_addr, CEPH_MAX_MON, GFP_KERNEL); 318 if (!opt->mon_addr) { 319 kfree(opt); 320 return NULL; 321 } 322 323 opt->flags = CEPH_OPT_DEFAULT; 324 opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT; 325 opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; 326 opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT; 327 opt->osd_request_timeout = CEPH_OSD_REQUEST_TIMEOUT_DEFAULT; 328 opt->read_from_replica = CEPH_READ_FROM_REPLICA_DEFAULT; 329 opt->con_modes[0] = CEPH_CON_MODE_UNKNOWN; 330 opt->con_modes[1] = CEPH_CON_MODE_UNKNOWN; 331 return opt; 332 } 333 EXPORT_SYMBOL(ceph_alloc_options); 334 335 void ceph_destroy_options(struct ceph_options *opt) 336 { 337 dout("destroy_options %p\n", opt); 338 if (!opt) 339 return; 340 341 ceph_clear_crush_locs(&opt->crush_locs); 342 kfree(opt->name); 343 if (opt->key) { 344 ceph_crypto_key_destroy(opt->key); 345 kfree(opt->key); 346 } 347 kfree(opt->mon_addr); 348 kfree(opt); 349 } 350 EXPORT_SYMBOL(ceph_destroy_options); 351 352 /* get secret from key store */ 353 static int get_secret(struct ceph_crypto_key *dst, const char *name, 354 struct p_log *log) 355 { 356 struct key *ukey; 357 int key_err; 358 int err = 0; 359 struct ceph_crypto_key *ckey; 360 361 ukey = request_key(&key_type_ceph, name, NULL); 362 if (IS_ERR(ukey)) { 363 /* request_key errors don't map nicely to mount(2) 364 errors; don't even try, but still printk */ 365 key_err = PTR_ERR(ukey); 366 switch (key_err) { 367 case -ENOKEY: 368 error_plog(log, "Failed due to key not found: %s", 369 name); 370 break; 371 case -EKEYEXPIRED: 372 error_plog(log, "Failed due to expired key: %s", 373 name); 374 break; 375 case -EKEYREVOKED: 376 error_plog(log, "Failed due to revoked key: %s", 377 name); 378 break; 379 default: 380 error_plog(log, "Failed due to key error %d: %s", 381 key_err, name); 382 } 383 err = -EPERM; 384 goto out; 385 } 386 387 ckey = ukey->payload.data[0]; 388 err = ceph_crypto_key_clone(dst, ckey); 389 if (err) 390 goto out_key; 391 /* pass through, err is 0 */ 392 393 out_key: 394 key_put(ukey); 395 out: 396 return err; 397 } 398 399 int ceph_parse_mon_ips(const char *buf, size_t len, struct ceph_options *opt, 400 struct fc_log *l, char delim) 401 { 402 struct p_log log = {.prefix = "libceph", .log = l}; 403 int ret; 404 405 /* ip1[:port1][<delim>ip2[:port2]...] */ 406 ret = ceph_parse_ips(buf, buf + len, opt->mon_addr, CEPH_MAX_MON, 407 &opt->num_mon, delim); 408 if (ret) { 409 error_plog(&log, "Failed to parse monitor IPs: %d", ret); 410 return ret; 411 } 412 413 return 0; 414 } 415 EXPORT_SYMBOL(ceph_parse_mon_ips); 416 417 int ceph_parse_param(struct fs_parameter *param, struct ceph_options *opt, 418 struct fc_log *l) 419 { 420 struct fs_parse_result result; 421 int token, err; 422 struct p_log log = {.prefix = "libceph", .log = l}; 423 424 token = __fs_parse(&log, ceph_parameters, param, &result); 425 dout("%s fs_parse '%s' token %d\n", __func__, param->key, token); 426 if (token < 0) 427 return token; 428 429 switch (token) { 430 case Opt_ip: 431 err = ceph_parse_ips(param->string, 432 param->string + param->size, 433 &opt->my_addr, 1, NULL, ','); 434 if (err) { 435 error_plog(&log, "Failed to parse ip: %d", err); 436 return err; 437 } 438 opt->flags |= CEPH_OPT_MYIP; 439 break; 440 441 case Opt_fsid: 442 err = ceph_parse_fsid(param->string, &opt->fsid); 443 if (err) { 444 error_plog(&log, "Failed to parse fsid: %d", err); 445 return err; 446 } 447 opt->flags |= CEPH_OPT_FSID; 448 break; 449 case Opt_name: 450 kfree(opt->name); 451 opt->name = param->string; 452 param->string = NULL; 453 break; 454 case Opt_secret: 455 ceph_crypto_key_destroy(opt->key); 456 kfree(opt->key); 457 458 opt->key = kzalloc_obj(*opt->key, GFP_KERNEL); 459 if (!opt->key) 460 return -ENOMEM; 461 err = ceph_crypto_key_unarmor(opt->key, param->string); 462 if (err) { 463 error_plog(&log, "Failed to parse secret: %d", err); 464 return err; 465 } 466 break; 467 case Opt_key: 468 ceph_crypto_key_destroy(opt->key); 469 kfree(opt->key); 470 471 opt->key = kzalloc_obj(*opt->key, GFP_KERNEL); 472 if (!opt->key) 473 return -ENOMEM; 474 return get_secret(opt->key, param->string, &log); 475 case Opt_crush_location: 476 ceph_clear_crush_locs(&opt->crush_locs); 477 err = ceph_parse_crush_location(param->string, 478 &opt->crush_locs); 479 if (err) { 480 error_plog(&log, "Failed to parse CRUSH location: %d", 481 err); 482 return err; 483 } 484 break; 485 case Opt_read_from_replica: 486 switch (result.uint_32) { 487 case Opt_read_from_replica_no: 488 opt->read_from_replica = 0; 489 break; 490 case Opt_read_from_replica_balance: 491 opt->read_from_replica = CEPH_OSD_FLAG_BALANCE_READS; 492 break; 493 case Opt_read_from_replica_localize: 494 opt->read_from_replica = CEPH_OSD_FLAG_LOCALIZE_READS; 495 break; 496 default: 497 BUG(); 498 } 499 break; 500 case Opt_ms_mode: 501 switch (result.uint_32) { 502 case Opt_ms_mode_legacy: 503 opt->con_modes[0] = CEPH_CON_MODE_UNKNOWN; 504 opt->con_modes[1] = CEPH_CON_MODE_UNKNOWN; 505 break; 506 case Opt_ms_mode_crc: 507 opt->con_modes[0] = CEPH_CON_MODE_CRC; 508 opt->con_modes[1] = CEPH_CON_MODE_UNKNOWN; 509 break; 510 case Opt_ms_mode_secure: 511 opt->con_modes[0] = CEPH_CON_MODE_SECURE; 512 opt->con_modes[1] = CEPH_CON_MODE_UNKNOWN; 513 break; 514 case Opt_ms_mode_prefer_crc: 515 opt->con_modes[0] = CEPH_CON_MODE_CRC; 516 opt->con_modes[1] = CEPH_CON_MODE_SECURE; 517 break; 518 case Opt_ms_mode_prefer_secure: 519 opt->con_modes[0] = CEPH_CON_MODE_SECURE; 520 opt->con_modes[1] = CEPH_CON_MODE_CRC; 521 break; 522 default: 523 BUG(); 524 } 525 break; 526 527 case Opt_osdkeepalivetimeout: 528 /* 0 isn't well defined right now, reject it */ 529 if (result.uint_32 < 1 || result.uint_32 > INT_MAX / 1000) 530 goto out_of_range; 531 opt->osd_keepalive_timeout = 532 msecs_to_jiffies(result.uint_32 * 1000); 533 break; 534 case Opt_osd_idle_ttl: 535 /* 0 isn't well defined right now, reject it */ 536 if (result.uint_32 < 1 || result.uint_32 > INT_MAX / 1000) 537 goto out_of_range; 538 opt->osd_idle_ttl = msecs_to_jiffies(result.uint_32 * 1000); 539 break; 540 case Opt_mount_timeout: 541 /* 0 is "wait forever" (i.e. infinite timeout) */ 542 if (result.uint_32 > INT_MAX / 1000) 543 goto out_of_range; 544 opt->mount_timeout = msecs_to_jiffies(result.uint_32 * 1000); 545 break; 546 case Opt_osd_request_timeout: 547 /* 0 is "wait forever" (i.e. infinite timeout) */ 548 if (result.uint_32 > INT_MAX / 1000) 549 goto out_of_range; 550 opt->osd_request_timeout = 551 msecs_to_jiffies(result.uint_32 * 1000); 552 break; 553 554 case Opt_share: 555 if (!result.negated) 556 opt->flags &= ~CEPH_OPT_NOSHARE; 557 else 558 opt->flags |= CEPH_OPT_NOSHARE; 559 break; 560 case Opt_crc: 561 if (!result.negated) 562 opt->flags &= ~CEPH_OPT_NOCRC; 563 else 564 opt->flags |= CEPH_OPT_NOCRC; 565 break; 566 case Opt_cephx_require_signatures: 567 if (!result.negated) 568 warn_plog(&log, "Ignoring cephx_require_signatures"); 569 else 570 warn_plog(&log, "Ignoring nocephx_require_signatures, use nocephx_sign_messages"); 571 break; 572 case Opt_cephx_sign_messages: 573 if (!result.negated) 574 opt->flags &= ~CEPH_OPT_NOMSGSIGN; 575 else 576 opt->flags |= CEPH_OPT_NOMSGSIGN; 577 break; 578 case Opt_tcp_nodelay: 579 if (!result.negated) 580 opt->flags |= CEPH_OPT_TCP_NODELAY; 581 else 582 opt->flags &= ~CEPH_OPT_TCP_NODELAY; 583 break; 584 585 case Opt_abort_on_full: 586 opt->flags |= CEPH_OPT_ABORT_ON_FULL; 587 break; 588 case Opt_rxbounce: 589 opt->flags |= CEPH_OPT_RXBOUNCE; 590 break; 591 592 default: 593 BUG(); 594 } 595 596 return 0; 597 598 out_of_range: 599 return inval_plog(&log, "%s out of range", param->key); 600 } 601 EXPORT_SYMBOL(ceph_parse_param); 602 603 int ceph_print_client_options(struct seq_file *m, struct ceph_client *client, 604 bool show_all) 605 { 606 struct ceph_options *opt = client->options; 607 size_t pos = m->count; 608 struct rb_node *n; 609 610 if (opt->name) { 611 seq_puts(m, "name="); 612 seq_escape(m, opt->name, ", \t\n\\"); 613 seq_putc(m, ','); 614 } 615 if (opt->key) 616 seq_puts(m, "secret=<hidden>,"); 617 618 if (!RB_EMPTY_ROOT(&opt->crush_locs)) { 619 seq_puts(m, "crush_location="); 620 for (n = rb_first(&opt->crush_locs); ; ) { 621 struct crush_loc_node *loc = 622 rb_entry(n, struct crush_loc_node, cl_node); 623 624 seq_printf(m, "%s:%s", loc->cl_loc.cl_type_name, 625 loc->cl_loc.cl_name); 626 n = rb_next(n); 627 if (!n) 628 break; 629 630 seq_putc(m, '|'); 631 } 632 seq_putc(m, ','); 633 } 634 if (opt->read_from_replica == CEPH_OSD_FLAG_BALANCE_READS) { 635 seq_puts(m, "read_from_replica=balance,"); 636 } else if (opt->read_from_replica == CEPH_OSD_FLAG_LOCALIZE_READS) { 637 seq_puts(m, "read_from_replica=localize,"); 638 } 639 if (opt->con_modes[0] != CEPH_CON_MODE_UNKNOWN) { 640 if (opt->con_modes[0] == CEPH_CON_MODE_CRC && 641 opt->con_modes[1] == CEPH_CON_MODE_UNKNOWN) { 642 seq_puts(m, "ms_mode=crc,"); 643 } else if (opt->con_modes[0] == CEPH_CON_MODE_SECURE && 644 opt->con_modes[1] == CEPH_CON_MODE_UNKNOWN) { 645 seq_puts(m, "ms_mode=secure,"); 646 } else if (opt->con_modes[0] == CEPH_CON_MODE_CRC && 647 opt->con_modes[1] == CEPH_CON_MODE_SECURE) { 648 seq_puts(m, "ms_mode=prefer-crc,"); 649 } else if (opt->con_modes[0] == CEPH_CON_MODE_SECURE && 650 opt->con_modes[1] == CEPH_CON_MODE_CRC) { 651 seq_puts(m, "ms_mode=prefer-secure,"); 652 } 653 } 654 655 if (opt->flags & CEPH_OPT_FSID) 656 seq_printf(m, "fsid=%pU,", &opt->fsid); 657 if (opt->flags & CEPH_OPT_NOSHARE) 658 seq_puts(m, "noshare,"); 659 if (opt->flags & CEPH_OPT_NOCRC) 660 seq_puts(m, "nocrc,"); 661 if (opt->flags & CEPH_OPT_NOMSGSIGN) 662 seq_puts(m, "nocephx_sign_messages,"); 663 if ((opt->flags & CEPH_OPT_TCP_NODELAY) == 0) 664 seq_puts(m, "notcp_nodelay,"); 665 if (show_all && (opt->flags & CEPH_OPT_ABORT_ON_FULL)) 666 seq_puts(m, "abort_on_full,"); 667 if (opt->flags & CEPH_OPT_RXBOUNCE) 668 seq_puts(m, "rxbounce,"); 669 670 if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT) 671 seq_printf(m, "mount_timeout=%d,", 672 jiffies_to_msecs(opt->mount_timeout) / 1000); 673 if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT) 674 seq_printf(m, "osd_idle_ttl=%d,", 675 jiffies_to_msecs(opt->osd_idle_ttl) / 1000); 676 if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT) 677 seq_printf(m, "osdkeepalivetimeout=%d,", 678 jiffies_to_msecs(opt->osd_keepalive_timeout) / 1000); 679 if (opt->osd_request_timeout != CEPH_OSD_REQUEST_TIMEOUT_DEFAULT) 680 seq_printf(m, "osd_request_timeout=%d,", 681 jiffies_to_msecs(opt->osd_request_timeout) / 1000); 682 683 /* drop redundant comma */ 684 if (m->count != pos) 685 m->count--; 686 687 return 0; 688 } 689 EXPORT_SYMBOL(ceph_print_client_options); 690 691 struct ceph_entity_addr *ceph_client_addr(struct ceph_client *client) 692 { 693 return &client->msgr.inst.addr; 694 } 695 EXPORT_SYMBOL(ceph_client_addr); 696 697 u64 ceph_client_gid(struct ceph_client *client) 698 { 699 return client->monc.auth->global_id; 700 } 701 EXPORT_SYMBOL(ceph_client_gid); 702 703 /* 704 * create a fresh client instance 705 */ 706 struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private) 707 { 708 struct ceph_client *client; 709 struct ceph_entity_addr *myaddr = NULL; 710 int err; 711 712 err = wait_for_random_bytes(); 713 if (err < 0) 714 return ERR_PTR(err); 715 716 client = kzalloc_obj(*client, GFP_KERNEL); 717 if (client == NULL) 718 return ERR_PTR(-ENOMEM); 719 720 client->private = private; 721 client->options = opt; 722 723 mutex_init(&client->mount_mutex); 724 init_waitqueue_head(&client->auth_wq); 725 client->auth_err = 0; 726 727 client->extra_mon_dispatch = NULL; 728 client->supported_features = CEPH_FEATURES_SUPPORTED_DEFAULT; 729 client->required_features = CEPH_FEATURES_REQUIRED_DEFAULT; 730 731 if (!ceph_test_opt(client, NOMSGSIGN)) 732 client->required_features |= CEPH_FEATURE_MSG_AUTH; 733 734 /* msgr */ 735 if (ceph_test_opt(client, MYIP)) 736 myaddr = &client->options->my_addr; 737 738 ceph_messenger_init(&client->msgr, myaddr); 739 740 /* subsystems */ 741 err = ceph_monc_init(&client->monc, client); 742 if (err < 0) 743 goto fail; 744 err = ceph_osdc_init(&client->osdc, client); 745 if (err < 0) 746 goto fail_monc; 747 748 return client; 749 750 fail_monc: 751 ceph_monc_stop(&client->monc); 752 fail: 753 ceph_messenger_fini(&client->msgr); 754 kfree(client); 755 return ERR_PTR(err); 756 } 757 EXPORT_SYMBOL(ceph_create_client); 758 759 void ceph_destroy_client(struct ceph_client *client) 760 { 761 dout("destroy_client %p\n", client); 762 763 atomic_set(&client->msgr.stopping, 1); 764 765 /* unmount */ 766 ceph_osdc_stop(&client->osdc); 767 ceph_monc_stop(&client->monc); 768 ceph_messenger_fini(&client->msgr); 769 770 ceph_debugfs_client_cleanup(client); 771 772 ceph_destroy_options(client->options); 773 774 kfree(client); 775 dout("destroy_client %p done\n", client); 776 } 777 EXPORT_SYMBOL(ceph_destroy_client); 778 779 void ceph_reset_client_addr(struct ceph_client *client) 780 { 781 ceph_messenger_reset_nonce(&client->msgr); 782 ceph_monc_reopen_session(&client->monc); 783 ceph_osdc_reopen_osds(&client->osdc); 784 } 785 EXPORT_SYMBOL(ceph_reset_client_addr); 786 787 /* 788 * mount: join the ceph cluster, and open root directory. 789 */ 790 int __ceph_open_session(struct ceph_client *client) 791 { 792 DEFINE_WAIT_FUNC(wait, woken_wake_function); 793 long timeout = ceph_timeout_jiffies(client->options->mount_timeout); 794 bool have_monmap, have_osdmap; 795 int err; 796 797 /* open session, and wait for mon and osd maps */ 798 err = ceph_monc_open_session(&client->monc); 799 if (err < 0) 800 return err; 801 802 add_wait_queue(&client->auth_wq, &wait); 803 for (;;) { 804 mutex_lock(&client->monc.mutex); 805 err = client->auth_err; 806 have_monmap = client->monc.monmap && client->monc.monmap->epoch; 807 mutex_unlock(&client->monc.mutex); 808 809 down_read(&client->osdc.lock); 810 have_osdmap = client->osdc.osdmap && client->osdc.osdmap->epoch; 811 up_read(&client->osdc.lock); 812 813 if (err || (have_monmap && have_osdmap)) 814 break; 815 816 if (signal_pending(current)) { 817 err = -ERESTARTSYS; 818 break; 819 } 820 821 if (!timeout) { 822 err = -ETIMEDOUT; 823 break; 824 } 825 826 /* wait */ 827 dout("mount waiting for mon_map\n"); 828 timeout = wait_woken(&wait, TASK_INTERRUPTIBLE, timeout); 829 } 830 remove_wait_queue(&client->auth_wq, &wait); 831 832 if (err) 833 return err; 834 835 pr_info("client%llu fsid %pU\n", ceph_client_gid(client), 836 &client->fsid); 837 ceph_debugfs_client_init(client); 838 839 return 0; 840 } 841 EXPORT_SYMBOL(__ceph_open_session); 842 843 int ceph_open_session(struct ceph_client *client) 844 { 845 int ret; 846 847 dout("open_session start\n"); 848 mutex_lock(&client->mount_mutex); 849 850 ret = __ceph_open_session(client); 851 852 mutex_unlock(&client->mount_mutex); 853 return ret; 854 } 855 EXPORT_SYMBOL(ceph_open_session); 856 857 int ceph_wait_for_latest_osdmap(struct ceph_client *client, 858 unsigned long timeout) 859 { 860 u64 newest_epoch; 861 int ret; 862 863 ret = ceph_monc_get_version(&client->monc, "osdmap", &newest_epoch); 864 if (ret) 865 return ret; 866 867 if (client->osdc.osdmap->epoch >= newest_epoch) 868 return 0; 869 870 ceph_osdc_maybe_request_map(&client->osdc); 871 return ceph_monc_wait_osdmap(&client->monc, newest_epoch, timeout); 872 } 873 EXPORT_SYMBOL(ceph_wait_for_latest_osdmap); 874 875 static int __init init_ceph_lib(void) 876 { 877 int ret = 0; 878 879 ceph_debugfs_init(); 880 881 ret = ceph_crypto_init(); 882 if (ret < 0) 883 goto out_debugfs; 884 885 ret = ceph_msgr_init(); 886 if (ret < 0) 887 goto out_crypto; 888 889 ret = ceph_osdc_setup(); 890 if (ret < 0) 891 goto out_msgr; 892 893 pr_info("loaded (mon/osd proto %d/%d)\n", 894 CEPH_MONC_PROTOCOL, CEPH_OSDC_PROTOCOL); 895 896 return 0; 897 898 out_msgr: 899 ceph_msgr_exit(); 900 out_crypto: 901 ceph_crypto_shutdown(); 902 out_debugfs: 903 ceph_debugfs_cleanup(); 904 return ret; 905 } 906 907 static void __exit exit_ceph_lib(void) 908 { 909 dout("exit_ceph_lib\n"); 910 WARN_ON(!ceph_strings_empty()); 911 912 ceph_osdc_cleanup(); 913 ceph_msgr_exit(); 914 ceph_crypto_shutdown(); 915 ceph_debugfs_cleanup(); 916 } 917 918 module_init(init_ceph_lib); 919 module_exit(exit_ceph_lib); 920 921 MODULE_AUTHOR("Sage Weil <sage@newdream.net>"); 922 MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>"); 923 MODULE_AUTHOR("Patience Warnick <patience@newdream.net>"); 924 MODULE_DESCRIPTION("Ceph core library"); 925 MODULE_LICENSE("GPL"); 926