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