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