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