linux/net/ceph/ceph_common.c
<<
>>
Prefs
   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 */
  42bool libceph_compatible(void *data)
  43{
  44        return true;
  45}
  46EXPORT_SYMBOL(libceph_compatible);
  47
  48/*
  49 * find filename portion of a path (/foo/bar/baz -> baz)
  50 */
  51const 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}
  59EXPORT_SYMBOL(ceph_file_part);
  60
  61const 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}
  93EXPORT_SYMBOL(ceph_msg_type_name);
  94
  95/*
  96 * Initially learn our fsid, or verify an fsid matches.
  97 */
  98int 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}
 111EXPORT_SYMBOL(ceph_check_fsid);
 112
 113static 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
 124int 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}
 180EXPORT_SYMBOL(ceph_compare_options);
 181
 182void *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
 194static 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 */
 228enum {
 229        Opt_osdtimeout,
 230        Opt_osdkeepalivetimeout,
 231        Opt_mount_timeout,
 232        Opt_osd_idle_ttl,
 233        Opt_last_int,
 234        /* int args above */
 235        Opt_fsid,
 236        Opt_name,
 237        Opt_secret,
 238        Opt_key,
 239        Opt_ip,
 240        Opt_last_string,
 241        /* string args above */
 242        Opt_share,
 243        Opt_noshare,
 244        Opt_crc,
 245        Opt_nocrc,
 246        Opt_cephx_require_signatures,
 247        Opt_nocephx_require_signatures,
 248        Opt_tcp_nodelay,
 249        Opt_notcp_nodelay,
 250};
 251
 252static match_table_t opt_tokens = {
 253        {Opt_osdtimeout, "osdtimeout=%d"},
 254        {Opt_osdkeepalivetimeout, "osdkeepalive=%d"},
 255        {Opt_mount_timeout, "mount_timeout=%d"},
 256        {Opt_osd_idle_ttl, "osd_idle_ttl=%d"},
 257        /* int args above */
 258        {Opt_fsid, "fsid=%s"},
 259        {Opt_name, "name=%s"},
 260        {Opt_secret, "secret=%s"},
 261        {Opt_key, "key=%s"},
 262        {Opt_ip, "ip=%s"},
 263        /* string args above */
 264        {Opt_share, "share"},
 265        {Opt_noshare, "noshare"},
 266        {Opt_crc, "crc"},
 267        {Opt_nocrc, "nocrc"},
 268        {Opt_cephx_require_signatures, "cephx_require_signatures"},
 269        {Opt_nocephx_require_signatures, "nocephx_require_signatures"},
 270        {Opt_tcp_nodelay, "tcp_nodelay"},
 271        {Opt_notcp_nodelay, "notcp_nodelay"},
 272        {-1, NULL}
 273};
 274
 275void ceph_destroy_options(struct ceph_options *opt)
 276{
 277        dout("destroy_options %p\n", opt);
 278        kfree(opt->name);
 279        if (opt->key) {
 280                ceph_crypto_key_destroy(opt->key);
 281                kfree(opt->key);
 282        }
 283        kfree(opt->mon_addr);
 284        kfree(opt);
 285}
 286EXPORT_SYMBOL(ceph_destroy_options);
 287
 288/* get secret from key store */
 289static int get_secret(struct ceph_crypto_key *dst, const char *name) {
 290        struct key *ukey;
 291        int key_err;
 292        int err = 0;
 293        struct ceph_crypto_key *ckey;
 294
 295        ukey = request_key(&key_type_ceph, name, NULL);
 296        if (!ukey || IS_ERR(ukey)) {
 297                /* request_key errors don't map nicely to mount(2)
 298                   errors; don't even try, but still printk */
 299                key_err = PTR_ERR(ukey);
 300                switch (key_err) {
 301                case -ENOKEY:
 302                        pr_warn("ceph: Mount failed due to key not found: %s\n",
 303                                name);
 304                        break;
 305                case -EKEYEXPIRED:
 306                        pr_warn("ceph: Mount failed due to expired key: %s\n",
 307                                name);
 308                        break;
 309                case -EKEYREVOKED:
 310                        pr_warn("ceph: Mount failed due to revoked key: %s\n",
 311                                name);
 312                        break;
 313                default:
 314                        pr_warn("ceph: Mount failed due to unknown key error %d: %s\n",
 315                                key_err, name);
 316                }
 317                err = -EPERM;
 318                goto out;
 319        }
 320
 321        ckey = ukey->payload.data;
 322        err = ceph_crypto_key_clone(dst, ckey);
 323        if (err)
 324                goto out_key;
 325        /* pass through, err is 0 */
 326
 327out_key:
 328        key_put(ukey);
 329out:
 330        return err;
 331}
 332
 333struct ceph_options *
 334ceph_parse_options(char *options, const char *dev_name,
 335                        const char *dev_name_end,
 336                        int (*parse_extra_token)(char *c, void *private),
 337                        void *private)
 338{
 339        struct ceph_options *opt;
 340        const char *c;
 341        int err = -ENOMEM;
 342        substring_t argstr[MAX_OPT_ARGS];
 343
 344        opt = kzalloc(sizeof(*opt), GFP_KERNEL);
 345        if (!opt)
 346                return ERR_PTR(-ENOMEM);
 347        opt->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*opt->mon_addr),
 348                                GFP_KERNEL);
 349        if (!opt->mon_addr)
 350                goto out;
 351
 352        dout("parse_options %p options '%s' dev_name '%s'\n", opt, options,
 353             dev_name);
 354
 355        /* start with defaults */
 356        opt->flags = CEPH_OPT_DEFAULT;
 357        opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT;
 358        opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT;
 359        opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT;
 360        opt->monc_ping_timeout = CEPH_MONC_PING_TIMEOUT_DEFAULT;
 361
 362        /* get mon ip(s) */
 363        /* ip1[:port1][,ip2[:port2]...] */
 364        err = ceph_parse_ips(dev_name, dev_name_end, opt->mon_addr,
 365                             CEPH_MAX_MON, &opt->num_mon);
 366        if (err < 0)
 367                goto out;
 368
 369        /* parse mount options */
 370        while ((c = strsep(&options, ",")) != NULL) {
 371                int token, intval, ret;
 372                if (!*c)
 373                        continue;
 374                err = -EINVAL;
 375                token = match_token((char *)c, opt_tokens, argstr);
 376                if (token < 0 && parse_extra_token) {
 377                        /* extra? */
 378                        err = parse_extra_token((char *)c, private);
 379                        if (err < 0) {
 380                                pr_err("bad option at '%s'\n", c);
 381                                goto out;
 382                        }
 383                        continue;
 384                }
 385                if (token < Opt_last_int) {
 386                        ret = match_int(&argstr[0], &intval);
 387                        if (ret < 0) {
 388                                pr_err("bad mount option arg (not int) "
 389                                       "at '%s'\n", c);
 390                                continue;
 391                        }
 392                        dout("got int token %d val %d\n", token, intval);
 393                } else if (token > Opt_last_int && token < Opt_last_string) {
 394                        dout("got string token %d val %s\n", token,
 395                             argstr[0].from);
 396                } else {
 397                        dout("got token %d\n", token);
 398                }
 399                switch (token) {
 400                case Opt_ip:
 401                        err = ceph_parse_ips(argstr[0].from,
 402                                             argstr[0].to,
 403                                             &opt->my_addr,
 404                                             1, NULL);
 405                        if (err < 0)
 406                                goto out;
 407                        opt->flags |= CEPH_OPT_MYIP;
 408                        break;
 409
 410                case Opt_fsid:
 411                        err = parse_fsid(argstr[0].from, &opt->fsid);
 412                        if (err == 0)
 413                                opt->flags |= CEPH_OPT_FSID;
 414                        break;
 415                case Opt_name:
 416                        opt->name = kstrndup(argstr[0].from,
 417                                              argstr[0].to-argstr[0].from,
 418                                              GFP_KERNEL);
 419                        break;
 420                case Opt_secret:
 421                        opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
 422                        if (!opt->key) {
 423                                err = -ENOMEM;
 424                                goto out;
 425                        }
 426                        err = ceph_crypto_key_unarmor(opt->key, argstr[0].from);
 427                        if (err < 0)
 428                                goto out;
 429                        break;
 430                case Opt_key:
 431                        opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
 432                        if (!opt->key) {
 433                                err = -ENOMEM;
 434                                goto out;
 435                        }
 436                        err = get_secret(opt->key, argstr[0].from);
 437                        if (err < 0)
 438                                goto out;
 439                        break;
 440
 441                        /* misc */
 442                case Opt_osdtimeout:
 443                        pr_warn("ignoring deprecated osdtimeout option\n");
 444                        break;
 445                case Opt_osdkeepalivetimeout:
 446                        /* 0 isn't well defined right now, reject it */
 447                        if (intval < 1 || intval > INT_MAX / 1000) {
 448                                pr_err("osdkeepalive out of range\n");
 449                                err = -EINVAL;
 450                                goto out;
 451                        }
 452                        opt->osd_keepalive_timeout =
 453                                        msecs_to_jiffies(intval * 1000);
 454                        break;
 455                case Opt_osd_idle_ttl:
 456                        /* 0 isn't well defined right now, reject it */
 457                        if (intval < 1 || intval > INT_MAX / 1000) {
 458                                pr_err("osd_idle_ttl out of range\n");
 459                                err = -EINVAL;
 460                                goto out;
 461                        }
 462                        opt->osd_idle_ttl = msecs_to_jiffies(intval * 1000);
 463                        break;
 464                case Opt_mount_timeout:
 465                        /* 0 is "wait forever" (i.e. infinite timeout) */
 466                        if (intval < 0 || intval > INT_MAX / 1000) {
 467                                pr_err("mount_timeout out of range\n");
 468                                err = -EINVAL;
 469                                goto out;
 470                        }
 471                        opt->mount_timeout = msecs_to_jiffies(intval * 1000);
 472                        break;
 473
 474                case Opt_share:
 475                        opt->flags &= ~CEPH_OPT_NOSHARE;
 476                        break;
 477                case Opt_noshare:
 478                        opt->flags |= CEPH_OPT_NOSHARE;
 479                        break;
 480
 481                case Opt_crc:
 482                        opt->flags &= ~CEPH_OPT_NOCRC;
 483                        break;
 484                case Opt_nocrc:
 485                        opt->flags |= CEPH_OPT_NOCRC;
 486                        break;
 487
 488                case Opt_cephx_require_signatures:
 489                        opt->flags &= ~CEPH_OPT_NOMSGAUTH;
 490                        break;
 491                case Opt_nocephx_require_signatures:
 492                        opt->flags |= CEPH_OPT_NOMSGAUTH;
 493                        break;
 494
 495                case Opt_tcp_nodelay:
 496                        opt->flags |= CEPH_OPT_TCP_NODELAY;
 497                        break;
 498                case Opt_notcp_nodelay:
 499                        opt->flags &= ~CEPH_OPT_TCP_NODELAY;
 500                        break;
 501
 502                default:
 503                        BUG_ON(token);
 504                }
 505        }
 506
 507        /* success */
 508        return opt;
 509
 510out:
 511        ceph_destroy_options(opt);
 512        return ERR_PTR(err);
 513}
 514EXPORT_SYMBOL(ceph_parse_options);
 515
 516int ceph_print_client_options(struct seq_file *m, struct ceph_client *client)
 517{
 518        struct ceph_options *opt = client->options;
 519        size_t pos = m->count;
 520
 521        if (opt->name) {
 522                seq_puts(m, "name=");
 523                seq_escape(m, opt->name, ", \t\n\\");
 524                seq_putc(m, ',');
 525        }
 526        if (opt->key)
 527                seq_puts(m, "secret=<hidden>,");
 528
 529        if (opt->flags & CEPH_OPT_FSID)
 530                seq_printf(m, "fsid=%pU,", &opt->fsid);
 531        if (opt->flags & CEPH_OPT_NOSHARE)
 532                seq_puts(m, "noshare,");
 533        if (opt->flags & CEPH_OPT_NOCRC)
 534                seq_puts(m, "nocrc,");
 535        if (opt->flags & CEPH_OPT_NOMSGAUTH)
 536                seq_puts(m, "nocephx_require_signatures,");
 537        if ((opt->flags & CEPH_OPT_TCP_NODELAY) == 0)
 538                seq_puts(m, "notcp_nodelay,");
 539
 540        if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT)
 541                seq_printf(m, "mount_timeout=%d,",
 542                           jiffies_to_msecs(opt->mount_timeout) / 1000);
 543        if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT)
 544                seq_printf(m, "osd_idle_ttl=%d,",
 545                           jiffies_to_msecs(opt->osd_idle_ttl) / 1000);
 546        if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT)
 547                seq_printf(m, "osdkeepalivetimeout=%d,",
 548                    jiffies_to_msecs(opt->osd_keepalive_timeout) / 1000);
 549
 550        /* drop redundant comma */
 551        if (m->count != pos)
 552                m->count--;
 553
 554        return 0;
 555}
 556EXPORT_SYMBOL(ceph_print_client_options);
 557
 558u64 ceph_client_id(struct ceph_client *client)
 559{
 560        return client->monc.auth->global_id;
 561}
 562EXPORT_SYMBOL(ceph_client_id);
 563
 564/*
 565 * create a fresh client instance
 566 */
 567struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private,
 568                                       u64 supported_features,
 569                                       u64 required_features)
 570{
 571        struct ceph_client *client;
 572        struct ceph_entity_addr *myaddr = NULL;
 573        int err = -ENOMEM;
 574
 575        client = kzalloc(sizeof(*client), GFP_KERNEL);
 576        if (client == NULL)
 577                return ERR_PTR(-ENOMEM);
 578
 579        client->private = private;
 580        client->options = opt;
 581
 582        mutex_init(&client->mount_mutex);
 583        init_waitqueue_head(&client->auth_wq);
 584        client->auth_err = 0;
 585
 586        if (!ceph_test_opt(client, NOMSGAUTH))
 587                required_features |= CEPH_FEATURE_MSG_AUTH;
 588
 589        client->extra_mon_dispatch = NULL;
 590        client->supported_features = CEPH_FEATURES_SUPPORTED_DEFAULT |
 591                supported_features;
 592        client->required_features = CEPH_FEATURES_REQUIRED_DEFAULT |
 593                required_features;
 594
 595        /* msgr */
 596        if (ceph_test_opt(client, MYIP))
 597                myaddr = &client->options->my_addr;
 598
 599        ceph_messenger_init(&client->msgr, myaddr,
 600                client->supported_features,
 601                client->required_features,
 602                ceph_test_opt(client, NOCRC),
 603                ceph_test_opt(client, TCP_NODELAY));
 604
 605        /* subsystems */
 606        err = ceph_monc_init(&client->monc, client);
 607        if (err < 0)
 608                goto fail;
 609        err = ceph_osdc_init(&client->osdc, client);
 610        if (err < 0)
 611                goto fail_monc;
 612
 613        return client;
 614
 615fail_monc:
 616        ceph_monc_stop(&client->monc);
 617fail:
 618        ceph_messenger_fini(&client->msgr);
 619        kfree(client);
 620        return ERR_PTR(err);
 621}
 622EXPORT_SYMBOL(ceph_create_client);
 623
 624void ceph_destroy_client(struct ceph_client *client)
 625{
 626        dout("destroy_client %p\n", client);
 627
 628        atomic_set(&client->msgr.stopping, 1);
 629
 630        /* unmount */
 631        ceph_osdc_stop(&client->osdc);
 632        ceph_monc_stop(&client->monc);
 633        ceph_messenger_fini(&client->msgr);
 634
 635        ceph_debugfs_client_cleanup(client);
 636
 637        ceph_destroy_options(client->options);
 638
 639        kfree(client);
 640        dout("destroy_client %p done\n", client);
 641}
 642EXPORT_SYMBOL(ceph_destroy_client);
 643
 644/*
 645 * true if we have the mon map (and have thus joined the cluster)
 646 */
 647static int have_mon_and_osd_map(struct ceph_client *client)
 648{
 649        return client->monc.monmap && client->monc.monmap->epoch &&
 650               client->osdc.osdmap && client->osdc.osdmap->epoch;
 651}
 652
 653/*
 654 * mount: join the ceph cluster, and open root directory.
 655 */
 656int __ceph_open_session(struct ceph_client *client, unsigned long started)
 657{
 658        unsigned long timeout = client->options->mount_timeout;
 659        long err;
 660
 661        /* open session, and wait for mon and osd maps */
 662        err = ceph_monc_open_session(&client->monc);
 663        if (err < 0)
 664                return err;
 665
 666        while (!have_mon_and_osd_map(client)) {
 667                if (timeout && time_after_eq(jiffies, started + timeout))
 668                        return -ETIMEDOUT;
 669
 670                /* wait */
 671                dout("mount waiting for mon_map\n");
 672                err = wait_event_interruptible_timeout(client->auth_wq,
 673                        have_mon_and_osd_map(client) || (client->auth_err < 0),
 674                        ceph_timeout_jiffies(timeout));
 675                if (err < 0)
 676                        return err;
 677                if (client->auth_err < 0)
 678                        return client->auth_err;
 679        }
 680
 681        return 0;
 682}
 683EXPORT_SYMBOL(__ceph_open_session);
 684
 685
 686int ceph_open_session(struct ceph_client *client)
 687{
 688        int ret;
 689        unsigned long started = jiffies;  /* note the start time */
 690
 691        dout("open_session start\n");
 692        mutex_lock(&client->mount_mutex);
 693
 694        ret = __ceph_open_session(client, started);
 695
 696        mutex_unlock(&client->mount_mutex);
 697        return ret;
 698}
 699EXPORT_SYMBOL(ceph_open_session);
 700
 701
 702static int __init init_ceph_lib(void)
 703{
 704        int ret = 0;
 705
 706        ret = ceph_debugfs_init();
 707        if (ret < 0)
 708                goto out;
 709
 710        ret = ceph_crypto_init();
 711        if (ret < 0)
 712                goto out_debugfs;
 713
 714        ret = ceph_msgr_init();
 715        if (ret < 0)
 716                goto out_crypto;
 717
 718        ret = ceph_osdc_setup();
 719        if (ret < 0)
 720                goto out_msgr;
 721
 722        pr_info("loaded (mon/osd proto %d/%d)\n",
 723                CEPH_MONC_PROTOCOL, CEPH_OSDC_PROTOCOL);
 724
 725        return 0;
 726
 727out_msgr:
 728        ceph_msgr_exit();
 729out_crypto:
 730        ceph_crypto_shutdown();
 731out_debugfs:
 732        ceph_debugfs_cleanup();
 733out:
 734        return ret;
 735}
 736
 737static void __exit exit_ceph_lib(void)
 738{
 739        dout("exit_ceph_lib\n");
 740        ceph_osdc_cleanup();
 741        ceph_msgr_exit();
 742        ceph_crypto_shutdown();
 743        ceph_debugfs_cleanup();
 744}
 745
 746module_init(init_ceph_lib);
 747module_exit(exit_ceph_lib);
 748
 749MODULE_AUTHOR("Sage Weil <sage@newdream.net>");
 750MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>");
 751MODULE_AUTHOR("Patience Warnick <patience@newdream.net>");
 752MODULE_DESCRIPTION("Ceph core library");
 753MODULE_LICENSE("GPL");
 754