linux/fs/ceph/super.c
<<
>>
Prefs
   1
   2#include <linux/ceph/ceph_debug.h>
   3
   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/module.h>
  10#include <linux/mount.h>
  11#include <linux/parser.h>
  12#include <linux/sched.h>
  13#include <linux/seq_file.h>
  14#include <linux/slab.h>
  15#include <linux/statfs.h>
  16#include <linux/string.h>
  17
  18#include "super.h"
  19#include "mds_client.h"
  20
  21#include <linux/ceph/ceph_features.h>
  22#include <linux/ceph/decode.h>
  23#include <linux/ceph/mon_client.h>
  24#include <linux/ceph/auth.h>
  25#include <linux/ceph/debugfs.h>
  26
  27/*
  28 * Ceph superblock operations
  29 *
  30 * Handle the basics of mounting, unmounting.
  31 */
  32
  33/*
  34 * super ops
  35 */
  36static void ceph_put_super(struct super_block *s)
  37{
  38        struct ceph_fs_client *fsc = ceph_sb_to_client(s);
  39
  40        dout("put_super\n");
  41        ceph_mdsc_close_sessions(fsc->mdsc);
  42
  43        /*
  44         * ensure we release the bdi before put_anon_super releases
  45         * the device name.
  46         */
  47        if (s->s_bdi == &fsc->backing_dev_info) {
  48                bdi_unregister(&fsc->backing_dev_info);
  49                s->s_bdi = NULL;
  50        }
  51
  52        return;
  53}
  54
  55static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
  56{
  57        struct ceph_fs_client *fsc = ceph_inode_to_client(dentry->d_inode);
  58        struct ceph_monmap *monmap = fsc->client->monc.monmap;
  59        struct ceph_statfs st;
  60        u64 fsid;
  61        int err;
  62
  63        dout("statfs\n");
  64        err = ceph_monc_do_statfs(&fsc->client->monc, &st);
  65        if (err < 0)
  66                return err;
  67
  68        /* fill in kstatfs */
  69        buf->f_type = CEPH_SUPER_MAGIC;  /* ?? */
  70
  71        /*
  72         * express utilization in terms of large blocks to avoid
  73         * overflow on 32-bit machines.
  74         */
  75        buf->f_bsize = 1 << CEPH_BLOCK_SHIFT;
  76        buf->f_blocks = le64_to_cpu(st.kb) >> (CEPH_BLOCK_SHIFT-10);
  77        buf->f_bfree = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10);
  78        buf->f_bavail = le64_to_cpu(st.kb_avail) >> (CEPH_BLOCK_SHIFT-10);
  79
  80        buf->f_files = le64_to_cpu(st.num_objects);
  81        buf->f_ffree = -1;
  82        buf->f_namelen = NAME_MAX;
  83        buf->f_frsize = PAGE_CACHE_SIZE;
  84
  85        /* leave fsid little-endian, regardless of host endianness */
  86        fsid = *(u64 *)(&monmap->fsid) ^ *((u64 *)&monmap->fsid + 1);
  87        buf->f_fsid.val[0] = fsid & 0xffffffff;
  88        buf->f_fsid.val[1] = fsid >> 32;
  89
  90        return 0;
  91}
  92
  93
  94static int ceph_sync_fs(struct super_block *sb, int wait)
  95{
  96        struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
  97
  98        if (!wait) {
  99                dout("sync_fs (non-blocking)\n");
 100                ceph_flush_dirty_caps(fsc->mdsc);
 101                dout("sync_fs (non-blocking) done\n");
 102                return 0;
 103        }
 104
 105        dout("sync_fs (blocking)\n");
 106        ceph_osdc_sync(&fsc->client->osdc);
 107        ceph_mdsc_sync(fsc->mdsc);
 108        dout("sync_fs (blocking) done\n");
 109        return 0;
 110}
 111
 112/*
 113 * mount options
 114 */
 115enum {
 116        Opt_wsize,
 117        Opt_rsize,
 118        Opt_rasize,
 119        Opt_caps_wanted_delay_min,
 120        Opt_caps_wanted_delay_max,
 121        Opt_cap_release_safety,
 122        Opt_readdir_max_entries,
 123        Opt_readdir_max_bytes,
 124        Opt_congestion_kb,
 125        Opt_last_int,
 126        /* int args above */
 127        Opt_snapdirname,
 128        Opt_last_string,
 129        /* string args above */
 130        Opt_dirstat,
 131        Opt_nodirstat,
 132        Opt_rbytes,
 133        Opt_norbytes,
 134        Opt_asyncreaddir,
 135        Opt_noasyncreaddir,
 136        Opt_dcache,
 137        Opt_nodcache,
 138        Opt_ino32,
 139        Opt_noino32,
 140};
 141
 142static match_table_t fsopt_tokens = {
 143        {Opt_wsize, "wsize=%d"},
 144        {Opt_rsize, "rsize=%d"},
 145        {Opt_rasize, "rasize=%d"},
 146        {Opt_caps_wanted_delay_min, "caps_wanted_delay_min=%d"},
 147        {Opt_caps_wanted_delay_max, "caps_wanted_delay_max=%d"},
 148        {Opt_cap_release_safety, "cap_release_safety=%d"},
 149        {Opt_readdir_max_entries, "readdir_max_entries=%d"},
 150        {Opt_readdir_max_bytes, "readdir_max_bytes=%d"},
 151        {Opt_congestion_kb, "write_congestion_kb=%d"},
 152        /* int args above */
 153        {Opt_snapdirname, "snapdirname=%s"},
 154        /* string args above */
 155        {Opt_dirstat, "dirstat"},
 156        {Opt_nodirstat, "nodirstat"},
 157        {Opt_rbytes, "rbytes"},
 158        {Opt_norbytes, "norbytes"},
 159        {Opt_asyncreaddir, "asyncreaddir"},
 160        {Opt_noasyncreaddir, "noasyncreaddir"},
 161        {Opt_dcache, "dcache"},
 162        {Opt_nodcache, "nodcache"},
 163        {Opt_ino32, "ino32"},
 164        {Opt_noino32, "noino32"},
 165        {-1, NULL}
 166};
 167
 168static int parse_fsopt_token(char *c, void *private)
 169{
 170        struct ceph_mount_options *fsopt = private;
 171        substring_t argstr[MAX_OPT_ARGS];
 172        int token, intval, ret;
 173
 174        token = match_token((char *)c, fsopt_tokens, argstr);
 175        if (token < 0)
 176                return -EINVAL;
 177
 178        if (token < Opt_last_int) {
 179                ret = match_int(&argstr[0], &intval);
 180                if (ret < 0) {
 181                        pr_err("bad mount option arg (not int) "
 182                               "at '%s'\n", c);
 183                        return ret;
 184                }
 185                dout("got int token %d val %d\n", token, intval);
 186        } else if (token > Opt_last_int && token < Opt_last_string) {
 187                dout("got string token %d val %s\n", token,
 188                     argstr[0].from);
 189        } else {
 190                dout("got token %d\n", token);
 191        }
 192
 193        switch (token) {
 194        case Opt_snapdirname:
 195                kfree(fsopt->snapdir_name);
 196                fsopt->snapdir_name = kstrndup(argstr[0].from,
 197                                               argstr[0].to-argstr[0].from,
 198                                               GFP_KERNEL);
 199                if (!fsopt->snapdir_name)
 200                        return -ENOMEM;
 201                break;
 202
 203                /* misc */
 204        case Opt_wsize:
 205                fsopt->wsize = intval;
 206                break;
 207        case Opt_rsize:
 208                fsopt->rsize = intval;
 209                break;
 210        case Opt_rasize:
 211                fsopt->rasize = intval;
 212                break;
 213        case Opt_caps_wanted_delay_min:
 214                fsopt->caps_wanted_delay_min = intval;
 215                break;
 216        case Opt_caps_wanted_delay_max:
 217                fsopt->caps_wanted_delay_max = intval;
 218                break;
 219        case Opt_readdir_max_entries:
 220                fsopt->max_readdir = intval;
 221                break;
 222        case Opt_readdir_max_bytes:
 223                fsopt->max_readdir_bytes = intval;
 224                break;
 225        case Opt_congestion_kb:
 226                fsopt->congestion_kb = intval;
 227                break;
 228        case Opt_dirstat:
 229                fsopt->flags |= CEPH_MOUNT_OPT_DIRSTAT;
 230                break;
 231        case Opt_nodirstat:
 232                fsopt->flags &= ~CEPH_MOUNT_OPT_DIRSTAT;
 233                break;
 234        case Opt_rbytes:
 235                fsopt->flags |= CEPH_MOUNT_OPT_RBYTES;
 236                break;
 237        case Opt_norbytes:
 238                fsopt->flags &= ~CEPH_MOUNT_OPT_RBYTES;
 239                break;
 240        case Opt_asyncreaddir:
 241                fsopt->flags &= ~CEPH_MOUNT_OPT_NOASYNCREADDIR;
 242                break;
 243        case Opt_noasyncreaddir:
 244                fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR;
 245                break;
 246        case Opt_dcache:
 247                fsopt->flags |= CEPH_MOUNT_OPT_DCACHE;
 248                break;
 249        case Opt_nodcache:
 250                fsopt->flags &= ~CEPH_MOUNT_OPT_DCACHE;
 251                break;
 252        case Opt_ino32:
 253                fsopt->flags |= CEPH_MOUNT_OPT_INO32;
 254                break;
 255        case Opt_noino32:
 256                fsopt->flags &= ~CEPH_MOUNT_OPT_INO32;
 257                break;
 258        default:
 259                BUG_ON(token);
 260        }
 261        return 0;
 262}
 263
 264static void destroy_mount_options(struct ceph_mount_options *args)
 265{
 266        dout("destroy_mount_options %p\n", args);
 267        kfree(args->snapdir_name);
 268        kfree(args);
 269}
 270
 271static int strcmp_null(const char *s1, const char *s2)
 272{
 273        if (!s1 && !s2)
 274                return 0;
 275        if (s1 && !s2)
 276                return -1;
 277        if (!s1 && s2)
 278                return 1;
 279        return strcmp(s1, s2);
 280}
 281
 282static int compare_mount_options(struct ceph_mount_options *new_fsopt,
 283                                 struct ceph_options *new_opt,
 284                                 struct ceph_fs_client *fsc)
 285{
 286        struct ceph_mount_options *fsopt1 = new_fsopt;
 287        struct ceph_mount_options *fsopt2 = fsc->mount_options;
 288        int ofs = offsetof(struct ceph_mount_options, snapdir_name);
 289        int ret;
 290
 291        ret = memcmp(fsopt1, fsopt2, ofs);
 292        if (ret)
 293                return ret;
 294
 295        ret = strcmp_null(fsopt1->snapdir_name, fsopt2->snapdir_name);
 296        if (ret)
 297                return ret;
 298
 299        return ceph_compare_options(new_opt, fsc->client);
 300}
 301
 302static int parse_mount_options(struct ceph_mount_options **pfsopt,
 303                               struct ceph_options **popt,
 304                               int flags, char *options,
 305                               const char *dev_name,
 306                               const char **path)
 307{
 308        struct ceph_mount_options *fsopt;
 309        const char *dev_name_end;
 310        int err;
 311
 312        if (!dev_name || !*dev_name)
 313                return -EINVAL;
 314
 315        fsopt = kzalloc(sizeof(*fsopt), GFP_KERNEL);
 316        if (!fsopt)
 317                return -ENOMEM;
 318
 319        dout("parse_mount_options %p, dev_name '%s'\n", fsopt, dev_name);
 320
 321        fsopt->sb_flags = flags;
 322        fsopt->flags = CEPH_MOUNT_OPT_DEFAULT;
 323
 324        fsopt->rsize = CEPH_RSIZE_DEFAULT;
 325        fsopt->rasize = CEPH_RASIZE_DEFAULT;
 326        fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
 327        fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
 328        fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
 329        fsopt->cap_release_safety = CEPH_CAP_RELEASE_SAFETY_DEFAULT;
 330        fsopt->max_readdir = CEPH_MAX_READDIR_DEFAULT;
 331        fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
 332        fsopt->congestion_kb = default_congestion_kb();
 333
 334        /*
 335         * Distinguish the server list from the path in "dev_name".
 336         * Internally we do not include the leading '/' in the path.
 337         *
 338         * "dev_name" will look like:
 339         *     <server_spec>[,<server_spec>...]:[<path>]
 340         * where
 341         *     <server_spec> is <ip>[:<port>]
 342         *     <path> is optional, but if present must begin with '/'
 343         */
 344        dev_name_end = strchr(dev_name, '/');
 345        if (dev_name_end) {
 346                /* skip over leading '/' for path */
 347                *path = dev_name_end + 1;
 348        } else {
 349                /* path is empty */
 350                dev_name_end = dev_name + strlen(dev_name);
 351                *path = dev_name_end;
 352        }
 353        err = -EINVAL;
 354        dev_name_end--;         /* back up to ':' separator */
 355        if (*dev_name_end != ':') {
 356                pr_err("device name is missing path (no : separator in %s)\n",
 357                                dev_name);
 358                goto out;
 359        }
 360        dout("device name '%.*s'\n", (int)(dev_name_end - dev_name), dev_name);
 361        dout("server path '%s'\n", *path);
 362
 363        *popt = ceph_parse_options(options, dev_name, dev_name_end,
 364                                 parse_fsopt_token, (void *)fsopt);
 365        if (IS_ERR(*popt)) {
 366                err = PTR_ERR(*popt);
 367                goto out;
 368        }
 369
 370        /* success */
 371        *pfsopt = fsopt;
 372        return 0;
 373
 374out:
 375        destroy_mount_options(fsopt);
 376        return err;
 377}
 378
 379/**
 380 * ceph_show_options - Show mount options in /proc/mounts
 381 * @m: seq_file to write to
 382 * @root: root of that (sub)tree
 383 */
 384static int ceph_show_options(struct seq_file *m, struct dentry *root)
 385{
 386        struct ceph_fs_client *fsc = ceph_sb_to_client(root->d_sb);
 387        struct ceph_mount_options *fsopt = fsc->mount_options;
 388        struct ceph_options *opt = fsc->client->options;
 389
 390        if (opt->flags & CEPH_OPT_FSID)
 391                seq_printf(m, ",fsid=%pU", &opt->fsid);
 392        if (opt->flags & CEPH_OPT_NOSHARE)
 393                seq_puts(m, ",noshare");
 394        if (opt->flags & CEPH_OPT_NOCRC)
 395                seq_puts(m, ",nocrc");
 396
 397        if (opt->name)
 398                seq_printf(m, ",name=%s", opt->name);
 399        if (opt->key)
 400                seq_puts(m, ",secret=<hidden>");
 401
 402        if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT)
 403                seq_printf(m, ",mount_timeout=%d", opt->mount_timeout);
 404        if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT)
 405                seq_printf(m, ",osd_idle_ttl=%d", opt->osd_idle_ttl);
 406        if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT)
 407                seq_printf(m, ",osdkeepalivetimeout=%d",
 408                           opt->osd_keepalive_timeout);
 409
 410        if (fsopt->flags & CEPH_MOUNT_OPT_DIRSTAT)
 411                seq_puts(m, ",dirstat");
 412        if ((fsopt->flags & CEPH_MOUNT_OPT_RBYTES) == 0)
 413                seq_puts(m, ",norbytes");
 414        if (fsopt->flags & CEPH_MOUNT_OPT_NOASYNCREADDIR)
 415                seq_puts(m, ",noasyncreaddir");
 416        if (fsopt->flags & CEPH_MOUNT_OPT_DCACHE)
 417                seq_puts(m, ",dcache");
 418        else
 419                seq_puts(m, ",nodcache");
 420
 421        if (fsopt->wsize)
 422                seq_printf(m, ",wsize=%d", fsopt->wsize);
 423        if (fsopt->rsize != CEPH_RSIZE_DEFAULT)
 424                seq_printf(m, ",rsize=%d", fsopt->rsize);
 425        if (fsopt->rasize != CEPH_RASIZE_DEFAULT)
 426                seq_printf(m, ",rasize=%d", fsopt->rasize);
 427        if (fsopt->congestion_kb != default_congestion_kb())
 428                seq_printf(m, ",write_congestion_kb=%d", fsopt->congestion_kb);
 429        if (fsopt->caps_wanted_delay_min != CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT)
 430                seq_printf(m, ",caps_wanted_delay_min=%d",
 431                         fsopt->caps_wanted_delay_min);
 432        if (fsopt->caps_wanted_delay_max != CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT)
 433                seq_printf(m, ",caps_wanted_delay_max=%d",
 434                           fsopt->caps_wanted_delay_max);
 435        if (fsopt->cap_release_safety != CEPH_CAP_RELEASE_SAFETY_DEFAULT)
 436                seq_printf(m, ",cap_release_safety=%d",
 437                           fsopt->cap_release_safety);
 438        if (fsopt->max_readdir != CEPH_MAX_READDIR_DEFAULT)
 439                seq_printf(m, ",readdir_max_entries=%d", fsopt->max_readdir);
 440        if (fsopt->max_readdir_bytes != CEPH_MAX_READDIR_BYTES_DEFAULT)
 441                seq_printf(m, ",readdir_max_bytes=%d", fsopt->max_readdir_bytes);
 442        if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT))
 443                seq_printf(m, ",snapdirname=%s", fsopt->snapdir_name);
 444        return 0;
 445}
 446
 447/*
 448 * handle any mon messages the standard library doesn't understand.
 449 * return error if we don't either.
 450 */
 451static int extra_mon_dispatch(struct ceph_client *client, struct ceph_msg *msg)
 452{
 453        struct ceph_fs_client *fsc = client->private;
 454        int type = le16_to_cpu(msg->hdr.type);
 455
 456        switch (type) {
 457        case CEPH_MSG_MDS_MAP:
 458                ceph_mdsc_handle_map(fsc->mdsc, msg);
 459                return 0;
 460
 461        default:
 462                return -1;
 463        }
 464}
 465
 466/*
 467 * create a new fs client
 468 */
 469static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
 470                                        struct ceph_options *opt)
 471{
 472        struct ceph_fs_client *fsc;
 473        const unsigned supported_features =
 474                CEPH_FEATURE_FLOCK |
 475                CEPH_FEATURE_DIRLAYOUTHASH;
 476        const unsigned required_features = 0;
 477        int err = -ENOMEM;
 478
 479        fsc = kzalloc(sizeof(*fsc), GFP_KERNEL);
 480        if (!fsc)
 481                return ERR_PTR(-ENOMEM);
 482
 483        fsc->client = ceph_create_client(opt, fsc, supported_features,
 484                                         required_features);
 485        if (IS_ERR(fsc->client)) {
 486                err = PTR_ERR(fsc->client);
 487                goto fail;
 488        }
 489        fsc->client->extra_mon_dispatch = extra_mon_dispatch;
 490        fsc->client->monc.want_mdsmap = 1;
 491
 492        fsc->mount_options = fsopt;
 493
 494        fsc->sb = NULL;
 495        fsc->mount_state = CEPH_MOUNT_MOUNTING;
 496
 497        atomic_long_set(&fsc->writeback_count, 0);
 498
 499        err = bdi_init(&fsc->backing_dev_info);
 500        if (err < 0)
 501                goto fail_client;
 502
 503        err = -ENOMEM;
 504        /*
 505         * The number of concurrent works can be high but they don't need
 506         * to be processed in parallel, limit concurrency.
 507         */
 508        fsc->wb_wq = alloc_workqueue("ceph-writeback", 0, 1);
 509        if (fsc->wb_wq == NULL)
 510                goto fail_bdi;
 511        fsc->pg_inv_wq = alloc_workqueue("ceph-pg-invalid", 0, 1);
 512        if (fsc->pg_inv_wq == NULL)
 513                goto fail_wb_wq;
 514        fsc->trunc_wq = alloc_workqueue("ceph-trunc", 0, 1);
 515        if (fsc->trunc_wq == NULL)
 516                goto fail_pg_inv_wq;
 517
 518        /* set up mempools */
 519        err = -ENOMEM;
 520        fsc->wb_pagevec_pool = mempool_create_kmalloc_pool(10,
 521                              fsc->mount_options->wsize >> PAGE_CACHE_SHIFT);
 522        if (!fsc->wb_pagevec_pool)
 523                goto fail_trunc_wq;
 524
 525        /* caps */
 526        fsc->min_caps = fsopt->max_readdir;
 527
 528        return fsc;
 529
 530fail_trunc_wq:
 531        destroy_workqueue(fsc->trunc_wq);
 532fail_pg_inv_wq:
 533        destroy_workqueue(fsc->pg_inv_wq);
 534fail_wb_wq:
 535        destroy_workqueue(fsc->wb_wq);
 536fail_bdi:
 537        bdi_destroy(&fsc->backing_dev_info);
 538fail_client:
 539        ceph_destroy_client(fsc->client);
 540fail:
 541        kfree(fsc);
 542        return ERR_PTR(err);
 543}
 544
 545static void destroy_fs_client(struct ceph_fs_client *fsc)
 546{
 547        dout("destroy_fs_client %p\n", fsc);
 548
 549        destroy_workqueue(fsc->wb_wq);
 550        destroy_workqueue(fsc->pg_inv_wq);
 551        destroy_workqueue(fsc->trunc_wq);
 552
 553        bdi_destroy(&fsc->backing_dev_info);
 554
 555        mempool_destroy(fsc->wb_pagevec_pool);
 556
 557        destroy_mount_options(fsc->mount_options);
 558
 559        ceph_fs_debugfs_cleanup(fsc);
 560
 561        ceph_destroy_client(fsc->client);
 562
 563        kfree(fsc);
 564        dout("destroy_fs_client %p done\n", fsc);
 565}
 566
 567/*
 568 * caches
 569 */
 570struct kmem_cache *ceph_inode_cachep;
 571struct kmem_cache *ceph_cap_cachep;
 572struct kmem_cache *ceph_dentry_cachep;
 573struct kmem_cache *ceph_file_cachep;
 574
 575static void ceph_inode_init_once(void *foo)
 576{
 577        struct ceph_inode_info *ci = foo;
 578        inode_init_once(&ci->vfs_inode);
 579}
 580
 581static int __init init_caches(void)
 582{
 583        ceph_inode_cachep = kmem_cache_create("ceph_inode_info",
 584                                      sizeof(struct ceph_inode_info),
 585                                      __alignof__(struct ceph_inode_info),
 586                                      (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD),
 587                                      ceph_inode_init_once);
 588        if (ceph_inode_cachep == NULL)
 589                return -ENOMEM;
 590
 591        ceph_cap_cachep = KMEM_CACHE(ceph_cap,
 592                                     SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
 593        if (ceph_cap_cachep == NULL)
 594                goto bad_cap;
 595
 596        ceph_dentry_cachep = KMEM_CACHE(ceph_dentry_info,
 597                                        SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
 598        if (ceph_dentry_cachep == NULL)
 599                goto bad_dentry;
 600
 601        ceph_file_cachep = KMEM_CACHE(ceph_file_info,
 602                                      SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
 603        if (ceph_file_cachep == NULL)
 604                goto bad_file;
 605
 606        return 0;
 607
 608bad_file:
 609        kmem_cache_destroy(ceph_dentry_cachep);
 610bad_dentry:
 611        kmem_cache_destroy(ceph_cap_cachep);
 612bad_cap:
 613        kmem_cache_destroy(ceph_inode_cachep);
 614        return -ENOMEM;
 615}
 616
 617static void destroy_caches(void)
 618{
 619        /*
 620         * Make sure all delayed rcu free inodes are flushed before we
 621         * destroy cache.
 622         */
 623        rcu_barrier();
 624        kmem_cache_destroy(ceph_inode_cachep);
 625        kmem_cache_destroy(ceph_cap_cachep);
 626        kmem_cache_destroy(ceph_dentry_cachep);
 627        kmem_cache_destroy(ceph_file_cachep);
 628}
 629
 630
 631/*
 632 * ceph_umount_begin - initiate forced umount.  Tear down down the
 633 * mount, skipping steps that may hang while waiting for server(s).
 634 */
 635static void ceph_umount_begin(struct super_block *sb)
 636{
 637        struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
 638
 639        dout("ceph_umount_begin - starting forced umount\n");
 640        if (!fsc)
 641                return;
 642        fsc->mount_state = CEPH_MOUNT_SHUTDOWN;
 643        return;
 644}
 645
 646static const struct super_operations ceph_super_ops = {
 647        .alloc_inode    = ceph_alloc_inode,
 648        .destroy_inode  = ceph_destroy_inode,
 649        .write_inode    = ceph_write_inode,
 650        .sync_fs        = ceph_sync_fs,
 651        .put_super      = ceph_put_super,
 652        .show_options   = ceph_show_options,
 653        .statfs         = ceph_statfs,
 654        .umount_begin   = ceph_umount_begin,
 655};
 656
 657/*
 658 * Bootstrap mount by opening the root directory.  Note the mount
 659 * @started time from caller, and time out if this takes too long.
 660 */
 661static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
 662                                       const char *path,
 663                                       unsigned long started)
 664{
 665        struct ceph_mds_client *mdsc = fsc->mdsc;
 666        struct ceph_mds_request *req = NULL;
 667        int err;
 668        struct dentry *root;
 669
 670        /* open dir */
 671        dout("open_root_inode opening '%s'\n", path);
 672        req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_GETATTR, USE_ANY_MDS);
 673        if (IS_ERR(req))
 674                return ERR_CAST(req);
 675        req->r_path1 = kstrdup(path, GFP_NOFS);
 676        req->r_ino1.ino = CEPH_INO_ROOT;
 677        req->r_ino1.snap = CEPH_NOSNAP;
 678        req->r_started = started;
 679        req->r_timeout = fsc->client->options->mount_timeout * HZ;
 680        req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE);
 681        req->r_num_caps = 2;
 682        err = ceph_mdsc_do_request(mdsc, NULL, req);
 683        if (err == 0) {
 684                struct inode *inode = req->r_target_inode;
 685                req->r_target_inode = NULL;
 686                dout("open_root_inode success\n");
 687                if (ceph_ino(inode) == CEPH_INO_ROOT &&
 688                    fsc->sb->s_root == NULL) {
 689                        root = d_make_root(inode);
 690                        if (!root) {
 691                                root = ERR_PTR(-ENOMEM);
 692                                goto out;
 693                        }
 694                } else {
 695                        root = d_obtain_alias(inode);
 696                }
 697                ceph_init_dentry(root);
 698                dout("open_root_inode success, root dentry is %p\n", root);
 699        } else {
 700                root = ERR_PTR(err);
 701        }
 702out:
 703        ceph_mdsc_put_request(req);
 704        return root;
 705}
 706
 707
 708
 709
 710/*
 711 * mount: join the ceph cluster, and open root directory.
 712 */
 713static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc,
 714                      const char *path)
 715{
 716        int err;
 717        unsigned long started = jiffies;  /* note the start time */
 718        struct dentry *root;
 719        int first = 0;   /* first vfsmount for this super_block */
 720
 721        dout("mount start\n");
 722        mutex_lock(&fsc->client->mount_mutex);
 723
 724        err = __ceph_open_session(fsc->client, started);
 725        if (err < 0)
 726                goto out;
 727
 728        dout("mount opening root\n");
 729        root = open_root_dentry(fsc, "", started);
 730        if (IS_ERR(root)) {
 731                err = PTR_ERR(root);
 732                goto out;
 733        }
 734        if (fsc->sb->s_root) {
 735                dput(root);
 736        } else {
 737                fsc->sb->s_root = root;
 738                first = 1;
 739
 740                err = ceph_fs_debugfs_init(fsc);
 741                if (err < 0)
 742                        goto fail;
 743        }
 744
 745        if (path[0] == 0) {
 746                dget(root);
 747        } else {
 748                dout("mount opening base mountpoint\n");
 749                root = open_root_dentry(fsc, path, started);
 750                if (IS_ERR(root)) {
 751                        err = PTR_ERR(root);
 752                        goto fail;
 753                }
 754        }
 755
 756        fsc->mount_state = CEPH_MOUNT_MOUNTED;
 757        dout("mount success\n");
 758        mutex_unlock(&fsc->client->mount_mutex);
 759        return root;
 760
 761out:
 762        mutex_unlock(&fsc->client->mount_mutex);
 763        return ERR_PTR(err);
 764
 765fail:
 766        if (first) {
 767                dput(fsc->sb->s_root);
 768                fsc->sb->s_root = NULL;
 769        }
 770        goto out;
 771}
 772
 773static int ceph_set_super(struct super_block *s, void *data)
 774{
 775        struct ceph_fs_client *fsc = data;
 776        int ret;
 777
 778        dout("set_super %p data %p\n", s, data);
 779
 780        s->s_flags = fsc->mount_options->sb_flags;
 781        s->s_maxbytes = 1ULL << 40;  /* temp value until we get mdsmap */
 782
 783        s->s_fs_info = fsc;
 784        fsc->sb = s;
 785
 786        s->s_op = &ceph_super_ops;
 787        s->s_export_op = &ceph_export_ops;
 788
 789        s->s_time_gran = 1000;  /* 1000 ns == 1 us */
 790
 791        ret = set_anon_super(s, NULL);  /* what is that second arg for? */
 792        if (ret != 0)
 793                goto fail;
 794
 795        return ret;
 796
 797fail:
 798        s->s_fs_info = NULL;
 799        fsc->sb = NULL;
 800        return ret;
 801}
 802
 803/*
 804 * share superblock if same fs AND options
 805 */
 806static int ceph_compare_super(struct super_block *sb, void *data)
 807{
 808        struct ceph_fs_client *new = data;
 809        struct ceph_mount_options *fsopt = new->mount_options;
 810        struct ceph_options *opt = new->client->options;
 811        struct ceph_fs_client *other = ceph_sb_to_client(sb);
 812
 813        dout("ceph_compare_super %p\n", sb);
 814
 815        if (compare_mount_options(fsopt, opt, other)) {
 816                dout("monitor(s)/mount options don't match\n");
 817                return 0;
 818        }
 819        if ((opt->flags & CEPH_OPT_FSID) &&
 820            ceph_fsid_compare(&opt->fsid, &other->client->fsid)) {
 821                dout("fsid doesn't match\n");
 822                return 0;
 823        }
 824        if (fsopt->sb_flags != other->mount_options->sb_flags) {
 825                dout("flags differ\n");
 826                return 0;
 827        }
 828        return 1;
 829}
 830
 831/*
 832 * construct our own bdi so we can control readahead, etc.
 833 */
 834static atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0);
 835
 836static int ceph_register_bdi(struct super_block *sb,
 837                             struct ceph_fs_client *fsc)
 838{
 839        int err;
 840
 841        /* set ra_pages based on rasize mount option? */
 842        if (fsc->mount_options->rasize >= PAGE_CACHE_SIZE)
 843                fsc->backing_dev_info.ra_pages =
 844                        (fsc->mount_options->rasize + PAGE_CACHE_SIZE - 1)
 845                        >> PAGE_SHIFT;
 846        else
 847                fsc->backing_dev_info.ra_pages =
 848                        default_backing_dev_info.ra_pages;
 849
 850        err = bdi_register(&fsc->backing_dev_info, NULL, "ceph-%d",
 851                           atomic_long_inc_return(&bdi_seq));
 852        if (!err)
 853                sb->s_bdi = &fsc->backing_dev_info;
 854        return err;
 855}
 856
 857static struct dentry *ceph_mount(struct file_system_type *fs_type,
 858                       int flags, const char *dev_name, void *data)
 859{
 860        struct super_block *sb;
 861        struct ceph_fs_client *fsc;
 862        struct dentry *res;
 863        int err;
 864        int (*compare_super)(struct super_block *, void *) = ceph_compare_super;
 865        const char *path = NULL;
 866        struct ceph_mount_options *fsopt = NULL;
 867        struct ceph_options *opt = NULL;
 868
 869        dout("ceph_mount\n");
 870        err = parse_mount_options(&fsopt, &opt, flags, data, dev_name, &path);
 871        if (err < 0) {
 872                res = ERR_PTR(err);
 873                goto out_final;
 874        }
 875
 876        /* create client (which we may/may not use) */
 877        fsc = create_fs_client(fsopt, opt);
 878        if (IS_ERR(fsc)) {
 879                res = ERR_CAST(fsc);
 880                destroy_mount_options(fsopt);
 881                ceph_destroy_options(opt);
 882                goto out_final;
 883        }
 884
 885        err = ceph_mdsc_init(fsc);
 886        if (err < 0) {
 887                res = ERR_PTR(err);
 888                goto out;
 889        }
 890
 891        if (ceph_test_opt(fsc->client, NOSHARE))
 892                compare_super = NULL;
 893        sb = sget(fs_type, compare_super, ceph_set_super, flags, fsc);
 894        if (IS_ERR(sb)) {
 895                res = ERR_CAST(sb);
 896                goto out;
 897        }
 898
 899        if (ceph_sb_to_client(sb) != fsc) {
 900                ceph_mdsc_destroy(fsc);
 901                destroy_fs_client(fsc);
 902                fsc = ceph_sb_to_client(sb);
 903                dout("get_sb got existing client %p\n", fsc);
 904        } else {
 905                dout("get_sb using new client %p\n", fsc);
 906                err = ceph_register_bdi(sb, fsc);
 907                if (err < 0) {
 908                        res = ERR_PTR(err);
 909                        goto out_splat;
 910                }
 911        }
 912
 913        res = ceph_real_mount(fsc, path);
 914        if (IS_ERR(res))
 915                goto out_splat;
 916        dout("root %p inode %p ino %llx.%llx\n", res,
 917             res->d_inode, ceph_vinop(res->d_inode));
 918        return res;
 919
 920out_splat:
 921        ceph_mdsc_close_sessions(fsc->mdsc);
 922        deactivate_locked_super(sb);
 923        goto out_final;
 924
 925out:
 926        ceph_mdsc_destroy(fsc);
 927        destroy_fs_client(fsc);
 928out_final:
 929        dout("ceph_mount fail %ld\n", PTR_ERR(res));
 930        return res;
 931}
 932
 933static void ceph_kill_sb(struct super_block *s)
 934{
 935        struct ceph_fs_client *fsc = ceph_sb_to_client(s);
 936        dout("kill_sb %p\n", s);
 937        ceph_mdsc_pre_umount(fsc->mdsc);
 938        kill_anon_super(s);    /* will call put_super after sb is r/o */
 939        ceph_mdsc_destroy(fsc);
 940        destroy_fs_client(fsc);
 941}
 942
 943static struct file_system_type ceph_fs_type = {
 944        .owner          = THIS_MODULE,
 945        .name           = "ceph",
 946        .mount          = ceph_mount,
 947        .kill_sb        = ceph_kill_sb,
 948        .fs_flags       = FS_RENAME_DOES_D_MOVE,
 949};
 950
 951#define _STRINGIFY(x) #x
 952#define STRINGIFY(x) _STRINGIFY(x)
 953
 954static int __init init_ceph(void)
 955{
 956        int ret = init_caches();
 957        if (ret)
 958                goto out;
 959
 960        ceph_xattr_init();
 961        ret = register_filesystem(&ceph_fs_type);
 962        if (ret)
 963                goto out_icache;
 964
 965        pr_info("loaded (mds proto %d)\n", CEPH_MDSC_PROTOCOL);
 966
 967        return 0;
 968
 969out_icache:
 970        ceph_xattr_exit();
 971        destroy_caches();
 972out:
 973        return ret;
 974}
 975
 976static void __exit exit_ceph(void)
 977{
 978        dout("exit_ceph\n");
 979        unregister_filesystem(&ceph_fs_type);
 980        ceph_xattr_exit();
 981        destroy_caches();
 982}
 983
 984module_init(init_ceph);
 985module_exit(exit_ceph);
 986
 987MODULE_AUTHOR("Sage Weil <sage@newdream.net>");
 988MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>");
 989MODULE_AUTHOR("Patience Warnick <patience@newdream.net>");
 990MODULE_DESCRIPTION("Ceph filesystem for Linux");
 991MODULE_LICENSE("GPL");
 992
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.