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