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 /* any matching mon ip implies a match */ 180 for (i = 0; i < opt1->num_mon; i++) { 181 if (ceph_monmap_contains(client->monc.monmap, 182 &opt1->mon_addr[i])) 183 return 0; 184 } 185 return -1; 186 } 187 EXPORT_SYMBOL(ceph_compare_options); 188 189 /* 190 * kvmalloc() doesn't fall back to the vmalloc allocator unless flags are 191 * compatible with (a superset of) GFP_KERNEL. This is because while the 192 * actual pages are allocated with the specified flags, the page table pages 193 * are always allocated with GFP_KERNEL. 194 * 195 * ceph_kvmalloc() may be called with GFP_KERNEL, GFP_NOFS or GFP_NOIO. 196 */ 197 void *ceph_kvmalloc(size_t size, gfp_t flags) 198 { 199 void *p; 200 201 if ((flags & (__GFP_IO | __GFP_FS)) == (__GFP_IO | __GFP_FS)) { 202 p = kvmalloc(size, flags); 203 } else if ((flags & (__GFP_IO | __GFP_FS)) == __GFP_IO) { 204 unsigned int nofs_flag = memalloc_nofs_save(); 205 p = kvmalloc(size, GFP_KERNEL); 206 memalloc_nofs_restore(nofs_flag); 207 } else { 208 unsigned int noio_flag = memalloc_noio_save(); 209 p = kvmalloc(size, GFP_KERNEL); 210 memalloc_noio_restore(noio_flag); 211 } 212 213 return p; 214 } 215 216 static int parse_fsid(const char *str, struct ceph_fsid *fsid) 217 { 218 int i = 0; 219 char tmp[3]; 220 int err = -EINVAL; 221 int d; 222 223 dout("parse_fsid '%s'\n", str); 224 tmp[2] = 0; 225 while (*str && i < 16) { 226 if (ispunct(*str)) { 227 str++; 228 continue; 229 } 230 if (!isxdigit(str[0]) || !isxdigit(str[1])) 231 break; 232 tmp[0] = str[0]; 233 tmp[1] = str[1]; 234 if (sscanf(tmp, "%x", &d) < 1) 235 break; 236 fsid->fsid[i] = d & 0xff; 237 i++; 238 str += 2; 239 } 240 241 if (i == 16) 242 err = 0; 243 dout("parse_fsid ret %d got fsid %pU\n", err, fsid); 244 return err; 245 } 246 247 /* 248 * ceph options 249 */ 250 enum { 251 Opt_osdtimeout, 252 Opt_osdkeepalivetimeout, 253 Opt_mount_timeout, 254 Opt_osd_idle_ttl, 255 Opt_osd_request_timeout, 256 /* int args above */ 257 Opt_fsid, 258 Opt_name, 259 Opt_secret, 260 Opt_key, 261 Opt_ip, 262 /* string args above */ 263 Opt_share, 264 Opt_crc, 265 Opt_cephx_require_signatures, 266 Opt_cephx_sign_messages, 267 Opt_tcp_nodelay, 268 Opt_abort_on_full, 269 }; 270 271 static const struct fs_parameter_spec ceph_parameters[] = { 272 fsparam_flag ("abort_on_full", Opt_abort_on_full), 273 fsparam_flag_no ("cephx_require_signatures", Opt_cephx_require_signatures), 274 fsparam_flag_no ("cephx_sign_messages", Opt_cephx_sign_messages), 275 fsparam_flag_no ("crc", Opt_crc), 276 fsparam_string ("fsid", Opt_fsid), 277 fsparam_string ("ip", Opt_ip), 278 fsparam_string ("key", Opt_key), 279 fsparam_u32 ("mount_timeout", Opt_mount_timeout), 280 fsparam_string ("name", Opt_name), 281 fsparam_u32 ("osd_idle_ttl", Opt_osd_idle_ttl), 282 fsparam_u32 ("osd_request_timeout", Opt_osd_request_timeout), 283 fsparam_u32 ("osdkeepalive", Opt_osdkeepalivetimeout), 284 __fsparam (fs_param_is_s32, "osdtimeout", Opt_osdtimeout, 285 fs_param_deprecated, NULL), 286 fsparam_string ("secret", Opt_secret), 287 fsparam_flag_no ("share", Opt_share), 288 fsparam_flag_no ("tcp_nodelay", Opt_tcp_nodelay), 289 {} 290 }; 291 292 struct ceph_options *ceph_alloc_options(void) 293 { 294 struct ceph_options *opt; 295 296 opt = kzalloc(sizeof(*opt), GFP_KERNEL); 297 if (!opt) 298 return NULL; 299 300 opt->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*opt->mon_addr), 301 GFP_KERNEL); 302 if (!opt->mon_addr) { 303 kfree(opt); 304 return NULL; 305 } 306 307 opt->flags = CEPH_OPT_DEFAULT; 308 opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT; 309 opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; 310 opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT; 311 opt->osd_request_timeout = CEPH_OSD_REQUEST_TIMEOUT_DEFAULT; 312 return opt; 313 } 314 EXPORT_SYMBOL(ceph_alloc_options); 315 316 void ceph_destroy_options(struct ceph_options *opt) 317 { 318 dout("destroy_options %p\n", opt); 319 if (!opt) 320 return; 321 322 kfree(opt->name); 323 if (opt->key) { 324 ceph_crypto_key_destroy(opt->key); 325 kfree(opt->key); 326 } 327 kfree(opt->mon_addr); 328 kfree(opt); 329 } 330 EXPORT_SYMBOL(ceph_destroy_options); 331 332 /* get secret from key store */ 333 static int get_secret(struct ceph_crypto_key *dst, const char *name, 334 struct p_log *log) 335 { 336 struct key *ukey; 337 int key_err; 338 int err = 0; 339 struct ceph_crypto_key *ckey; 340 341 ukey = request_key(&key_type_ceph, name, NULL); 342 if (IS_ERR(ukey)) { 343 /* request_key errors don't map nicely to mount(2) 344 errors; don't even try, but still printk */ 345 key_err = PTR_ERR(ukey); 346 switch (key_err) { 347 case -ENOKEY: 348 error_plog(log, "Failed due to key not found: %s", 349 name); 350 break; 351 case -EKEYEXPIRED: 352 error_plog(log, "Failed due to expired key: %s", 353 name); 354 break; 355 case -EKEYREVOKED: 356 error_plog(log, "Failed due to revoked key: %s", 357 name); 358 break; 359 default: 360 error_plog(log, "Failed due to key error %d: %s", 361 key_err, name); 362 } 363 err = -EPERM; 364 goto out; 365 } 366 367 ckey = ukey->payload.data[0]; 368 err = ceph_crypto_key_clone(dst, ckey); 369 if (err) 370 goto out_key; 371 /* pass through, err is 0 */ 372 373 out_key: 374 key_put(ukey); 375 out: 376 return err; 377 } 378 379 int ceph_parse_mon_ips(const char *buf, size_t len, struct ceph_options *opt, 380 struct fc_log *l) 381 { 382 struct p_log log = {.prefix = "libceph", .log = l}; 383 int ret; 384 385 /* ip1[:port1][,ip2[:port2]...] */ 386 ret = ceph_parse_ips(buf, buf + len, opt->mon_addr, CEPH_MAX_MON, 387 &opt->num_mon); 388 if (ret) { 389 error_plog(&log, "Failed to parse monitor IPs: %d", ret); 390 return ret; 391 } 392 393 return 0; 394 } 395 EXPORT_SYMBOL(ceph_parse_mon_ips); 396 397 int ceph_parse_param(struct fs_parameter *param, struct ceph_options *opt, 398 struct fc_log *l) 399 { 400 struct fs_parse_result result; 401 int token, err; 402 struct p_log log = {.prefix = "libceph", .log = l}; 403 404 token = __fs_parse(&log, ceph_parameters, param, &result); 405 dout("%s fs_parse '%s' token %d\n", __func__, param->key, token); 406 if (token < 0) 407 return token; 408 409 switch (token) { 410 case Opt_ip: 411 err = ceph_parse_ips(param->string, 412 param->string + param->size, 413 &opt->my_addr, 414 1, NULL); 415 if (err) { 416 error_plog(&log, "Failed to parse ip: %d", err); 417 return err; 418 } 419 opt->flags |= CEPH_OPT_MYIP; 420 break; 421 422 case Opt_fsid: 423 err = parse_fsid(param->string, &opt->fsid); 424 if (err) { 425 error_plog(&log, "Failed to parse fsid: %d", err); 426 return err; 427 } 428 opt->flags |= CEPH_OPT_FSID; 429 break; 430 case Opt_name: 431 kfree(opt->name); 432 opt->name = param->string; 433 param->string = NULL; 434 break; 435 case Opt_secret: 436 ceph_crypto_key_destroy(opt->key); 437 kfree(opt->key); 438 439 opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL); 440 if (!opt->key) 441 return -ENOMEM; 442 err = ceph_crypto_key_unarmor(opt->key, param->string); 443 if (err) { 444 error_plog(&log, "Failed to parse secret: %d", err); 445 return err; 446 } 447 break; 448 case Opt_key: 449 ceph_crypto_key_destroy(opt->key); 450 kfree(opt->key); 451 452 opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL); 453 if (!opt->key) 454 return -ENOMEM; 455 return get_secret(opt->key, param->string, &log); 456 457 case Opt_osdtimeout: 458 warn_plog(&log, "Ignoring osdtimeout"); 459 break; 460 case Opt_osdkeepalivetimeout: 461 /* 0 isn't well defined right now, reject it */ 462 if (result.uint_32 < 1 || result.uint_32 > INT_MAX / 1000) 463 goto out_of_range; 464 opt->osd_keepalive_timeout = 465 msecs_to_jiffies(result.uint_32 * 1000); 466 break; 467 case Opt_osd_idle_ttl: 468 /* 0 isn't well defined right now, reject it */ 469 if (result.uint_32 < 1 || result.uint_32 > INT_MAX / 1000) 470 goto out_of_range; 471 opt->osd_idle_ttl = msecs_to_jiffies(result.uint_32 * 1000); 472 break; 473 case Opt_mount_timeout: 474 /* 0 is "wait forever" (i.e. infinite timeout) */ 475 if (result.uint_32 > INT_MAX / 1000) 476 goto out_of_range; 477 opt->mount_timeout = msecs_to_jiffies(result.uint_32 * 1000); 478 break; 479 case Opt_osd_request_timeout: 480 /* 0 is "wait forever" (i.e. infinite timeout) */ 481 if (result.uint_32 > INT_MAX / 1000) 482 goto out_of_range; 483 opt->osd_request_timeout = 484 msecs_to_jiffies(result.uint_32 * 1000); 485 break; 486 487 case Opt_share: 488 if (!result.negated) 489 opt->flags &= ~CEPH_OPT_NOSHARE; 490 else 491 opt->flags |= CEPH_OPT_NOSHARE; 492 break; 493 case Opt_crc: 494 if (!result.negated) 495 opt->flags &= ~CEPH_OPT_NOCRC; 496 else 497 opt->flags |= CEPH_OPT_NOCRC; 498 break; 499 case Opt_cephx_require_signatures: 500 if (!result.negated) 501 opt->flags &= ~CEPH_OPT_NOMSGAUTH; 502 else 503 opt->flags |= CEPH_OPT_NOMSGAUTH; 504 break; 505 case Opt_cephx_sign_messages: 506 if (!result.negated) 507 opt->flags &= ~CEPH_OPT_NOMSGSIGN; 508 else 509 opt->flags |= CEPH_OPT_NOMSGSIGN; 510 break; 511 case Opt_tcp_nodelay: 512 if (!result.negated) 513 opt->flags |= CEPH_OPT_TCP_NODELAY; 514 else 515 opt->flags &= ~CEPH_OPT_TCP_NODELAY; 516 break; 517 518 case Opt_abort_on_full: 519 opt->flags |= CEPH_OPT_ABORT_ON_FULL; 520 break; 521 522 default: 523 BUG(); 524 } 525 526 return 0; 527 528 out_of_range: 529 return inval_plog(&log, "%s out of range", param->key); 530 } 531 EXPORT_SYMBOL(ceph_parse_param); 532 533 int ceph_print_client_options(struct seq_file *m, struct ceph_client *client, 534 bool show_all) 535 { 536 struct ceph_options *opt = client->options; 537 size_t pos = m->count; 538 539 if (opt->name) { 540 seq_puts(m, "name="); 541 seq_escape(m, opt->name, ", \t\n\\"); 542 seq_putc(m, ','); 543 } 544 if (opt->key) 545 seq_puts(m, "secret=<hidden>,"); 546 547 if (opt->flags & CEPH_OPT_FSID) 548 seq_printf(m, "fsid=%pU,", &opt->fsid); 549 if (opt->flags & CEPH_OPT_NOSHARE) 550 seq_puts(m, "noshare,"); 551 if (opt->flags & CEPH_OPT_NOCRC) 552 seq_puts(m, "nocrc,"); 553 if (opt->flags & CEPH_OPT_NOMSGAUTH) 554 seq_puts(m, "nocephx_require_signatures,"); 555 if (opt->flags & CEPH_OPT_NOMSGSIGN) 556 seq_puts(m, "nocephx_sign_messages,"); 557 if ((opt->flags & CEPH_OPT_TCP_NODELAY) == 0) 558 seq_puts(m, "notcp_nodelay,"); 559 if (show_all && (opt->flags & CEPH_OPT_ABORT_ON_FULL)) 560 seq_puts(m, "abort_on_full,"); 561 562 if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT) 563 seq_printf(m, "mount_timeout=%d,", 564 jiffies_to_msecs(opt->mount_timeout) / 1000); 565 if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT) 566 seq_printf(m, "osd_idle_ttl=%d,", 567 jiffies_to_msecs(opt->osd_idle_ttl) / 1000); 568 if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT) 569 seq_printf(m, "osdkeepalivetimeout=%d,", 570 jiffies_to_msecs(opt->osd_keepalive_timeout) / 1000); 571 if (opt->osd_request_timeout != CEPH_OSD_REQUEST_TIMEOUT_DEFAULT) 572 seq_printf(m, "osd_request_timeout=%d,", 573 jiffies_to_msecs(opt->osd_request_timeout) / 1000); 574 575 /* drop redundant comma */ 576 if (m->count != pos) 577 m->count--; 578 579 return 0; 580 } 581 EXPORT_SYMBOL(ceph_print_client_options); 582 583 struct ceph_entity_addr *ceph_client_addr(struct ceph_client *client) 584 { 585 return &client->msgr.inst.addr; 586 } 587 EXPORT_SYMBOL(ceph_client_addr); 588 589 u64 ceph_client_gid(struct ceph_client *client) 590 { 591 return client->monc.auth->global_id; 592 } 593 EXPORT_SYMBOL(ceph_client_gid); 594 595 /* 596 * create a fresh client instance 597 */ 598 struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private) 599 { 600 struct ceph_client *client; 601 struct ceph_entity_addr *myaddr = NULL; 602 int err; 603 604 err = wait_for_random_bytes(); 605 if (err < 0) 606 return ERR_PTR(err); 607 608 client = kzalloc(sizeof(*client), GFP_KERNEL); 609 if (client == NULL) 610 return ERR_PTR(-ENOMEM); 611 612 client->private = private; 613 client->options = opt; 614 615 mutex_init(&client->mount_mutex); 616 init_waitqueue_head(&client->auth_wq); 617 client->auth_err = 0; 618 619 client->extra_mon_dispatch = NULL; 620 client->supported_features = CEPH_FEATURES_SUPPORTED_DEFAULT; 621 client->required_features = CEPH_FEATURES_REQUIRED_DEFAULT; 622 623 if (!ceph_test_opt(client, NOMSGAUTH)) 624 client->required_features |= CEPH_FEATURE_MSG_AUTH; 625 626 /* msgr */ 627 if (ceph_test_opt(client, MYIP)) 628 myaddr = &client->options->my_addr; 629 630 ceph_messenger_init(&client->msgr, myaddr); 631 632 /* subsystems */ 633 err = ceph_monc_init(&client->monc, client); 634 if (err < 0) 635 goto fail; 636 err = ceph_osdc_init(&client->osdc, client); 637 if (err < 0) 638 goto fail_monc; 639 640 return client; 641 642 fail_monc: 643 ceph_monc_stop(&client->monc); 644 fail: 645 ceph_messenger_fini(&client->msgr); 646 kfree(client); 647 return ERR_PTR(err); 648 } 649 EXPORT_SYMBOL(ceph_create_client); 650 651 void ceph_destroy_client(struct ceph_client *client) 652 { 653 dout("destroy_client %p\n", client); 654 655 atomic_set(&client->msgr.stopping, 1); 656 657 /* unmount */ 658 ceph_osdc_stop(&client->osdc); 659 ceph_monc_stop(&client->monc); 660 ceph_messenger_fini(&client->msgr); 661 662 ceph_debugfs_client_cleanup(client); 663 664 ceph_destroy_options(client->options); 665 666 kfree(client); 667 dout("destroy_client %p done\n", client); 668 } 669 EXPORT_SYMBOL(ceph_destroy_client); 670 671 void ceph_reset_client_addr(struct ceph_client *client) 672 { 673 ceph_messenger_reset_nonce(&client->msgr); 674 ceph_monc_reopen_session(&client->monc); 675 ceph_osdc_reopen_osds(&client->osdc); 676 } 677 EXPORT_SYMBOL(ceph_reset_client_addr); 678 679 /* 680 * true if we have the mon map (and have thus joined the cluster) 681 */ 682 static bool have_mon_and_osd_map(struct ceph_client *client) 683 { 684 return client->monc.monmap && client->monc.monmap->epoch && 685 client->osdc.osdmap && client->osdc.osdmap->epoch; 686 } 687 688 /* 689 * mount: join the ceph cluster, and open root directory. 690 */ 691 int __ceph_open_session(struct ceph_client *client, unsigned long started) 692 { 693 unsigned long timeout = client->options->mount_timeout; 694 long err; 695 696 /* open session, and wait for mon and osd maps */ 697 err = ceph_monc_open_session(&client->monc); 698 if (err < 0) 699 return err; 700 701 while (!have_mon_and_osd_map(client)) { 702 if (timeout && time_after_eq(jiffies, started + timeout)) 703 return -ETIMEDOUT; 704 705 /* wait */ 706 dout("mount waiting for mon_map\n"); 707 err = wait_event_interruptible_timeout(client->auth_wq, 708 have_mon_and_osd_map(client) || (client->auth_err < 0), 709 ceph_timeout_jiffies(timeout)); 710 if (err < 0) 711 return err; 712 if (client->auth_err < 0) 713 return client->auth_err; 714 } 715 716 pr_info("client%llu fsid %pU\n", ceph_client_gid(client), 717 &client->fsid); 718 ceph_debugfs_client_init(client); 719 720 return 0; 721 } 722 EXPORT_SYMBOL(__ceph_open_session); 723 724 int ceph_open_session(struct ceph_client *client) 725 { 726 int ret; 727 unsigned long started = jiffies; /* note the start time */ 728 729 dout("open_session start\n"); 730 mutex_lock(&client->mount_mutex); 731 732 ret = __ceph_open_session(client, started); 733 734 mutex_unlock(&client->mount_mutex); 735 return ret; 736 } 737 EXPORT_SYMBOL(ceph_open_session); 738 739 int ceph_wait_for_latest_osdmap(struct ceph_client *client, 740 unsigned long timeout) 741 { 742 u64 newest_epoch; 743 int ret; 744 745 ret = ceph_monc_get_version(&client->monc, "osdmap", &newest_epoch); 746 if (ret) 747 return ret; 748 749 if (client->osdc.osdmap->epoch >= newest_epoch) 750 return 0; 751 752 ceph_osdc_maybe_request_map(&client->osdc); 753 return ceph_monc_wait_osdmap(&client->monc, newest_epoch, timeout); 754 } 755 EXPORT_SYMBOL(ceph_wait_for_latest_osdmap); 756 757 static int __init init_ceph_lib(void) 758 { 759 int ret = 0; 760 761 ceph_debugfs_init(); 762 763 ret = ceph_crypto_init(); 764 if (ret < 0) 765 goto out_debugfs; 766 767 ret = ceph_msgr_init(); 768 if (ret < 0) 769 goto out_crypto; 770 771 ret = ceph_osdc_setup(); 772 if (ret < 0) 773 goto out_msgr; 774 775 pr_info("loaded (mon/osd proto %d/%d)\n", 776 CEPH_MONC_PROTOCOL, CEPH_OSDC_PROTOCOL); 777 778 return 0; 779 780 out_msgr: 781 ceph_msgr_exit(); 782 out_crypto: 783 ceph_crypto_shutdown(); 784 out_debugfs: 785 ceph_debugfs_cleanup(); 786 return ret; 787 } 788 789 static void __exit exit_ceph_lib(void) 790 { 791 dout("exit_ceph_lib\n"); 792 WARN_ON(!ceph_strings_empty()); 793 794 ceph_osdc_cleanup(); 795 ceph_msgr_exit(); 796 ceph_crypto_shutdown(); 797 ceph_debugfs_cleanup(); 798 } 799 800 module_init(init_ceph_lib); 801 module_exit(exit_ceph_lib); 802 803 MODULE_AUTHOR("Sage Weil <sage@newdream.net>"); 804 MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>"); 805 MODULE_AUTHOR("Patience Warnick <patience@newdream.net>"); 806 MODULE_DESCRIPTION("Ceph core library"); 807 MODULE_LICENSE("GPL"); 808